ACM程序设计竞赛例题1.docx

上传人:b****7 文档编号:9737131 上传时间:2023-02-06 格式:DOCX 页数:64 大小:34.85KB
下载 相关 举报
ACM程序设计竞赛例题1.docx_第1页
第1页 / 共64页
ACM程序设计竞赛例题1.docx_第2页
第2页 / 共64页
ACM程序设计竞赛例题1.docx_第3页
第3页 / 共64页
ACM程序设计竞赛例题1.docx_第4页
第4页 / 共64页
ACM程序设计竞赛例题1.docx_第5页
第5页 / 共64页
点击查看更多>>
下载资源
资源描述

ACM程序设计竞赛例题1.docx

《ACM程序设计竞赛例题1.docx》由会员分享,可在线阅读,更多相关《ACM程序设计竞赛例题1.docx(64页珍藏版)》请在冰豆网上搜索。

ACM程序设计竞赛例题1.docx

ACM程序设计竞赛例题1

备战ACM资料

习题

1.0-1背包问题

在0/1背包问题中,需对容量为c的背包进行装载。

从n个物品中选取装入背包的物品,每件物品i的重量为wi,价值为pi。

对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高。

程序如下:

#include

voidreaddata();

voidsearch(int);

voidcheckmax();

voidprintresult();

intc=35,n=10;//c:

背包容量;n:

物品数

intw[10],v[10];//w[i]、v[i]:

第i件物品的重量和价值

inta[10],max;//a数组存放当前解各物品选取情况;max:

记录最大价值

//a[i]=0表示不选第i件物品,a[i]=1表示选第i件物品

intmain()

{

readdata();//读入数据

search(0);//递归搜索

printresult();

}

voidsearch(intm)

{

if(m>=n)

checkmax();//检查当前解是否是可行解,若是则把它的价值与max比较

else

{

a[m]=0;//不选第m件物品

search(m+1);//递归搜索下一件物品

a[m]=1;//不选第m件物品

search(m+1);//递归搜索下一件物品

}

}

voidcheckmax()

{

inti,weight=0,value=0;

for(i=0;i

{

if(a[i]==1)//如果选取了该物品

{

weight=weight+w[i];//累加重量

value=value+v[i];//累加价值

}

}

if(weight<=c)//若为可行解

if(value>max)//且价值大于max

max=value;//替换max

}

voidreaddata()

{

inti;

for(i=0;i

scanf("%d%d",&w[i],&v[i]);//读入第i件物品重量和价值

}

voidprintresult()

{

printf("%d",max);

}

2.装载问题

有两艘船,载重量分别是c1、c2,n个集装箱,重量是wi(i=1…n),且所有集装箱的总重量不超过c1+c2。

确定是否有可能将所有集装箱全部装入两艘船。

提示:

求出不超过c1的最大值max,若总重量-max

3.堡垒问题(ZOJ1002)

如图城堡是一个4×4的方格,为了保卫城堡,现需要在某些格子里修建一些堡垒。

城堡中的某些格子是墙,其余格子都是空格,堡垒只能建在空格里,每个堡垒都可以向上下左右四个方向射击,如果两个堡垒在同一行或同一列,且中间没有墙相隔,则两个堡垒都会把对方打掉。

问对于给定的一种状态,最多能够修建几个堡垒。

程序主要部分如下:

intmain()

{

readdata();//读入数据

search(0);//递归搜索

printresult();

}

voidsearch(intm)

{

introw,col;

row=m/n;//求第m个格子的行号

col=m%n;//求第m个格子的列号

if(m>=n*n)

checkmax();//检查当前解是否是可行解,若是则把它的价值与max比较

else

{

search(m+1);//该位置不放堡垒递归搜索下一个位置

if(canplace(m))//判断第m个格子是否能放堡垒

{

place(m);//在第m个格子上放置一个堡垒

search(m+1);//递归搜索下一个位置

takeout(m);//去掉第m个格子上放置的堡垒

}

}

}

5.8皇后问题

在一个8×8的棋盘里放置8个皇后,要求这8个皇后两两之间互相都不“冲突”。

#include

#include

voidsearch(int);

voidprintresult();//打印结果

intcanplace(int,int);//判断该位置能否放置皇后

voidplace(int,int);//在该位置能否放置皇后

voidtakeout(int,int);//把该位置放置皇后去掉

inta[8];//a[i]存放第i个皇后的位置

intmain()

{

search(0);//递归搜索

}

voidsearch(intm)

{

inti;

if(m>=8)//当已经找出一组解时

printresult();//输出当前结果

else

{

for(i=0;i<8;i++)//对当前行0到7列的每一个位置

{

if(canplace(m,i))//判断第m个格子是否能放堡垒

{

place(m,i);//在(m,i)格子上放置一个皇后

search(m+1);//递归搜索下一行

takeout(m,i);//把(m,i)格子上的皇后去掉

}

}

}

}

intcanplace(introw,intcol)

{

inti;

for(i=0;i

if(abs(i-row)==abs(a[i]-col)||a[i]==col)

return(0);

return

(1);

}

voidplace(introw,intcol)

{

a[row]=col;

}

voidtakeout(introw,intcol)

{

a[row]=-1;

}

voidprintresult()

{

inti,j;

for(i=0;i<8;i++)

{

for(j=0;j<8;j++)

if(a[i]==j)

printf("A");

else

printf(".");

printf("\n");

}

printf("\n");

}

6.素数环问题

把从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数。

分析:

用回溯算法,考察所有可能的排列。

程序如下:

#include

#include

voidsearch(int);

voidinit();//初始化

voidprintresult();//打印结果

intisprime(int);//判断该数是否是素数

voidswap(int,int);//交换a[m]和a[i]

inta[21];//a数组存放素数环

intmain()

{

init();

search

(2);//递归搜索

}

intisprime(intnum)

{

inti,k;

k=sqrt(num);

for(i=2;i<=k;i++)

if(num%i==0)

return(0);

return

(1);

}

voidprintresult()

{

inti;

for(i=1;i<=20;i++)

printf("%3d",a[i]);

printf("\n");

}

voidsearch(intm)

{

inti;

if(m>20)//当已经搜索到叶结点时

{

if(isprime(a[1]+a[20]))//如果a[1]+a[20]也是素数

printresult();//输出当前解

return;

}

else

{

for(i=m;i<=20;i++)//(排列树)

{

swap(m,i);//交换a[m]和a[i]

if(isprime(a[m-1]+a[m]))//判断a[m-1]+a[m]是否是素数

search(m+1);//递归搜索下一个位置

swap(m,i);//把a[m]和a[i]换回来

}

}

}

voidswap(intm,inti)

{

intt;

t=a[m];

a[m]=a[i];

a[i]=t;

}

voidinit()

{

inti;

for(i=0;i<21;i++)

a[i]=i;

}

7.迷宫问题

给一个20×20的迷宫、起点坐标和终点坐标,问从起点是否能到达终点。

输入数据:

’.’表示空格;’X’表示墙。

程序如下:

#include

#include

voidsearch(int,int);

intcanplace(int,int);

voidreaddata();//读入数据

voidprintresult();//打印结果

inta[20][20];//a数组存放迷宫

ints,t;

intmain()

{

introw,col;

readdata();

row=s/20;

col=s%20;

search(row,col);//递归搜索

printresult();

}

voidsearch(introw,intcol)

{

intr,c;

a[row][col]=1;

r=row;//左

c=col-1;

if(canplace(r,c))//判断(r,c)位置是否已经走过

search(r,c);//递归搜索(r,c)

r=row+1;//下

c=col;

if(canplace(r,c))//判断(r,c)位置是否已经走过

search(r,c);//递归搜索(r,c)

r=row;//右

c=col+1;

if(canplace(r,c))//判断(r,c)位置是否已经走过

search(r,c);//递归搜索(r,c)

r=row-1;//上

c=col;

if(canplace(r,c))//判断(r,c)位置是否已经走过

search(r,c);//递归搜索(r,c)

}

voidprintresult()

{

inti,j;

for(i=0;i<20;i++)

{

for(j=0;j<20;j++)

printf("%3d",a[i][j]);

printf("\n");

}

}

voidreaddata()

{

inti,j;

for(i=0;i<20;i++)

{

for(j=0;j<20;j++)

scanf("%d",&a[i][j]);

}

}

intcanplace(introw,intcol)

{

if(row>=0&&row<20&&col>=0&&col<20&&a[row][col]==0)

return1;

else

return0;

}

}

1.Floodfill

给一个20×20的迷宫和一个起点坐标,用广度优先搜索填充所有的可到达的格子。

提示:

参考第2题。

2.电子老鼠闯迷宫

如下图12×12方格图,找出一条自入口(2,9)到出口(11,8)的最短路

本题给出完整的程序和一组测试数据。

状态:

老鼠所在的行、列。

程序如下:

#include

voidreaddata();//读入数据

voidinit();//初始化

intsearch();//广搜,并在每一个可到达的每一个空格出填上最小步数

intemptyopen();//判栈是否为空:

空:

1;非空:

0。

inttakeoutofopen();//从栈中取出一个元素,并把该元素从栈中删除

intcanmoveto(int,int,int*,int*,int);//判能否移动到该方向,并带回坐标(r,c)

intisaim(introw,intcol);//判断该点是否是目标

intused(int,int);//判断该点是否已经走过

voidaddtoopen(int,int);//把该点加入到open表

inta[12][12];//a存放迷宫,0表示空格,-2表示墙。

//广搜时,未找到目标以前到达的空格,填上到达该点的最小步数

intn;//n为迷宫边长,注:

若大于12,必须修改一些参数,如a的大小

intopen[20],head,tail,openlen=20;//open表

ints,t;//起点和终点

intmain()

{

intnumber;

readdata();//读取数据

init();//初始化

number=search();//广搜并返回最小步数

printf("%d",number);//打印结果

}

intsearch()

{

intu,row,col,r,c,i,num;

while(!

emptyopen())//当栈非空

{

u=takeoutofopen();//从栈中取出一个元素,并把该元素从栈中删除

row=u/n;//计算该点的坐标

col=u%n;

num=a[row][col];//取得该点的步数

for(i=0;i<4;i++)

{

if(canmoveto(row,col,&r,&c,i))//判能否移动到该方向,并带回坐标(r,c)

{

if(isaim(r,c))//如果是目标结点

return(num+1);//返回最小步数

if(!

used(r,c))//如果(r,c)还未到达过

{

a[r][c]=num+1;//记录该点的最小步数

addtoopen(r,c);//把该点加入到open表

}

}

}

}

}

intemptyopen()

{

if(head==tail)

return

(1);

else

return(0);

}

inttakeoutofopen()

{

intu;

if(head==tail)

{

printf("errer:

stackisempty");

return(-1);

}

u=open[head++];

head=head%openlen;

return(u);

}

intcanmoveto(introw,intcol,int*p,int*q,intdirection)

{

intr,c;

r=row;

c=col;

switch(direction)

{

case0:

c--;//左

break;

case1:

r++;//下

break;

case2:

c++;//右

break;

case3:

r--;//上

}

*p=r;

*q=c;

if(r<0||r>=n||c<0||c>=n)//如果越界返回0

return(0);

if(a[r][c]==0)//如果是空格返回1

return

(1);

return(0);//其余情况返回0

}

intisaim(introw,intcol)

{

if(row*n+col==t)

return

(1);

else

return(0);

}

intused(introw,intcol)

{

if(a[row][col]==0)//0表示空格

return(0);

else

return

(1);

}

voidaddtoopen(introw,intcol)

{

intu;

u=row*n+col;

open[tail++]=u;

tail=tail%openlen;

}

voidreaddata()

{

inti,j,row,col;

charstr[20];

scanf("%d",&n);

scanf("%d%d",&row,&col);//起点坐标

s=row*n+col;

scanf("%d%d",&row,&col);//终点坐标

t=row*n+col;

gets(str);

for(i=0;i

{

gets(str);

for(j=0;j

if(str[j]=='.')

a[i][j]=0;//0表示空格

else

a[i][j]=-2;//-2表示墙

}

}

voidinit()

{

head=0;

tail=1;

open[0]=s;

}

测试数据如下:

1210718

XXXXXXXXXXXX

X......X.XXX

X.X.XX.....X

X.X.XX.XXX.X

X.X.....X..X

X.XXXXXXXXXX

X...X.X....X

X.XXX...XXXX

X.....X....X

XXX.XXXX.X.X

XXXXXXX..XXX

XXXXXXXXXXXX

注:

测试数据可在运行时粘贴上去(点击窗口最左上角按钮,在菜单中选则“编辑”/“粘贴”即可)。

想一想:

此程序都存在哪些问题,如果openlen太小程序会不会出错,加入代码使程序能自动报出此类错误。

3.跳马

给一个200×200的棋盘,问国际象棋的马从给定的起点到给定的终点最少需要几步。

SampleInput0011Sampleoutput4

状态:

马所在的行、列。

程序如下:

#include

voidreaddata();//读入数据

voidinit();//初始化

intsearch();//广度优先搜索

intemptyopen();//判栈是否为空:

空:

1;非空:

0。

longtakeoutofopen();//从栈中取出一个元素,并把该元素从栈中删除

intcanmoveto(int,int,int*,int*,int);//判能否移动到该方向,并带回坐标(r,c)

intisaim(introw,intcol);//判断该点是否是目标

intused(int,int);//判断该点是否已经走过

voidaddtoopen(int,int);//把该点加入到open表

inta[200][200],n=200;//a存放棋盘,n为迷宫边长

longopen[2000],head,tail,openlen=2000;//open表1367

longs,t;//起点和终点

intsearch()

{

longu;

introw,col,r,c,i,num;

while(!

emptyopen())//当栈非空

{

u=takeoutofopen();//从栈中取出一个元素,并把该元素从栈中删除

row=u/n;//计算该点所在的行

col=u%n;//计算该点所在的列

num=a[row][col];//取得该点的步数

for(i=0;i<8;i++)

{

if(canmoveto(row,col,&r,&c,i))//判能否移动到该方向,并带回坐标(r,c)

{

if(isaim(r,c))//如果是目标结点

return(num+1);//返回最小步数

if(!

used(r,c))//如果(r,c)还未到达过

{

a[r][c]=num+1;//记录该点的最小步数

addtoopen(r,c);//把该点加入到open表

}

}

}

}

return-1;

}

intmain()//为了让search()显示在一页内和main函数换了以下

{//一般的算法程序main函数写在最上面读起来更方便

intnumber;

readdata();//读取数据

init();//初始化

number=search();//广搜并返回最小步数

printf("%d",number);//打印结果

}

intemptyopen()

{

if(head==tail)

return

(1);

else

return(0);

}

longtakeoutofopen()

{

longu;

if(head==tail)

{

printf("errer:

stackisempty");

return(-1);

}

u=open[head++];

head=head%openlen;

return(u);

}

intused(introw,intcol)

{

if(a[row][col]==0)

return(0);

else

return

(1);

}

voidaddtoopen(introw,intcol)

{

intu;

if((head-tail)%openlen==1)

printf("opentableoverflow");

u=row;

u=u*n+col;

open[tail++]=u;

tail=tail%openlen;

}

voidreaddata()

{

longrow,col;

scanf("%ld%ld",&row,&col);//起点坐标

s=row*n+col;

scanf("%ld%ld",&row,&col);//终点坐标

t=row*n+col;

}

voidinit()

{

head=0;

tail=1;

open[0]=s;

}

intisaim(introw,intcol)

{

if(row*n+col==t)

return

(1);

else

return(0);

}

思考:

参考第4题,改为用结构体表示状态写此程序。

4.独轮车

独轮车的轮子上有5种颜色,每走一格颜色变化一次,独轮车只能往前推,也可以在原地旋转,每走一格,需要一个单位的时

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 学习总结

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1