1、ACM程序设计竞赛例题1备战ACM资料习题1 0-1背包问题在0 / 1背包问题中,需对容量为c 的背包进行装载。从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高。 程序如下:#include void readdata();void search(int);void checkmax();void printresult();int c=35, n=10; /c: 背包容量;n:物品数int w10, v10; /wi、vi:第i件物品的重量和价值int a10, max;
2、/a数组存放当前解各物品选取情况;max:记录最大价值 /ai=0表示不选第i件物品,ai=1表示选第i件物品int main() readdata(); /读入数据 search(0); /递归搜索 printresult();void search(int m) if(m=n) checkmax(); /检查当前解是否是可行解,若是则把它的价值与max比较 else am=0; /不选第m件物品 search(m+1); /递归搜索下一件物品 am=1; /不选第m件物品 search(m+1); /递归搜索下一件物品 void checkmax() int i, weight=0, va
3、lue=0; for(i=0;in;i+) if(ai=1) /如果选取了该物品 weight = weight + wi; /累加重量 value = value + vi; /累加价值 if(weightmax) /且价值大于max max=value; /替换maxvoid readdata() int i; for(i=0;in;i+) scanf(%d%d,&wi,&vi); /读入第i件物品重量和价值void printresult() printf(%d,max);2 装载问题有两艘船,载重量分别是c1、 c2,n个集装箱,重量是wi (i=1n),且所有集装箱的总重量不超过c1
4、+c2。确定是否有可能将所有集装箱全部装入两艘船。提示:求出不超过c1的最大值max,若总重量max =n*n) checkmax(); /检查当前解是否是可行解,若是则把它的价值与max比较 else search(m+1); /该位置不放堡垒递归搜索下一个位置 if(canplace(m) /判断第m个格子是否能放堡垒 place(m); /在第m个格子上放置一个堡垒 search(m+1); /递归搜索下一个位置 takeout(m); /去掉第m个格子上放置的堡垒 5 8皇后问题在一个的棋盘里放置个皇后,要求这8个皇后两两之间互相都不“冲突”。#include #include voi
5、d search(int);void printresult(); /打印结果int canplace(int,int); /判断该位置能否放置皇后void place(int,int); /在该位置能否放置皇后void takeout(int,int); /把该位置放置皇后去掉int a8; /ai存放第i个皇后的位置int main() search(0); /递归搜索void search(int m) int i; if(m=8) /当已经找出一组解时 printresult(); /输出当前结果 else for(i=0;i8;i+) /对当前行0到7列的每一个位置 if(canpl
6、ace(m,i) /判断第m个格子是否能放堡垒 place(m,i); /在(m,i)格子上放置一个皇后 search(m+1); /递归搜索下一行 takeout(m,i); /把(m,i)格子上的皇后去掉 int canplace(int row, int col) int i; for(i=0;irow;i+) if(abs(i-row)=abs(ai-col)|ai=col) return(0); return(1);void place(int row, int col) arow=col;void takeout(int row, int col) arow=-1;void pri
7、ntresult() int i,j; for(i=0;i8;i+) for(j=0;j8;j+) if(ai=j) printf( A ); else printf( . ); printf(n); printf(n);6 素数环问题把从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数。分析:用回溯算法,考察所有可能的排列。程序如下:#include #include void search(int);void init(); /初始化void printresult(); /打印结果int isprime(int); /判断该数是否是素数void swap(int,int);
8、/交换am和aiint a21; /a数组存放素数环int main() init(); search(2); /递归搜索int isprime(int num) int i,k; k=sqrt(num); for(i=2;i=k;i+) if(num%i=0) return(0); return(1);void printresult() int i; for(i=1;i20) /当已经搜索到叶结点时 if(isprime(a1+a20) /如果a1+a20也是素数 printresult(); /输出当前解 return; else for(i=m;i=20;i+) /(排列树) swap
9、(m,i); /交换am和ai if(isprime(am-1+am) /判断am-1+am是否是素数 search(m+1); /递归搜索下一个位置 swap(m,i); /把am和ai换回来 void swap(int m, int i) int t; t=am; am=ai; ai=t;void init() int i; for(i=0;i21;i+) ai=i;7 迷宫问题给一个2020的迷宫、起点坐标和终点坐标,问从起点是否能到达终点。输入数据:.表示空格;X表示墙。程序如下:#include #include void search(int,int);int canplace(i
10、nt,int);void readdata(); /读入数据void printresult(); /打印结果int a2020; /a数组存放迷宫int s,t;int main() int row, col; readdata(); row=s/20; col=s%20; search(row,col); /递归搜索 printresult();void search(int row, int col) int r,c; arowcol=1; r=row; /左 c=col-1; if(canplace(r,c) /判断(r,c)位置是否已经走过 search(r,c); /递归搜索(r,
11、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)void printresult() int i,j; for(i=0;i20;i+) for(j=0;j20;j+) printf(
12、%3d,aij); printf(n); void readdata() int i,j; for(i=0;i20;i+) for(j=0;j=0&row=0&col20&arowcol=0) return 1; else return 0;1. Floodfill给一个2020的迷宫和一个起点坐标,用广度优先搜索填充所有的可到达的格子。提示:参考第2题。2. 电子老鼠闯迷宫如下图1212方格图,找出一条自入口(2,9)到出口(11,8)的最短路本题给出完整的程序和一组测试数据。状态:老鼠所在的行、列。程序如下:#includevoid readdata(); /读入数据void init()
13、; /初始化int search(); /广搜,并在每一个可到达的每一个空格出填上最小步数int emptyopen(); /判栈是否为空:空:1;非空:0。int takeoutofopen(); /从栈中取出一个元素,并把该元素从栈中删除int canmoveto(int,int,int*,int*,int); /判能否移动到该方向,并带回坐标(r,c)int isaim(int row, int col); /判断该点是否是目标int used(int,int); /判断该点是否已经走过void addtoopen(int,int); /把该点加入到open表int a1212; /a存
14、放迷宫,0表示空格,-2表示墙。 /广搜时,未找到目标以前到达的空格,填上到达该点的最小步数int n; /n为迷宫边长,注:若大于12,必须修改一些参数,如a的大小int open20,head,tail,openlen=20; /open表int s,t; /起点和终点int main() int number; readdata(); /读取数据 init(); /初始化 number=search(); /广搜并返回最小步数 printf(%d,number); /打印结果int search() int u, row, col, r, c, i, num; while(!emptyo
15、pen() /当栈非空 u=takeoutofopen(); /从栈中取出一个元素,并把该元素从栈中删除 row=u/n; /计算该点的坐标 col=u%n; num=arowcol; /取得该点的步数 for(i=0;i4;i+) if(canmoveto(row,col,&r,&c,i) /判能否移动到该方向,并带回坐标(r,c) if(isaim(r,c) /如果是目标结点 return(num+1); /返回最小步数 if(!used(r,c) /如果(r,c)还未到达过 arc=num+1; /记录该点的最小步数 addtoopen(r,c); /把该点加入到open表 int em
16、ptyopen() if(head=tail) return(1); else return(0);int takeoutofopen() int u; if(head=tail) printf(errer: stack is empty); return(-1); u=openhead+; head=head%openlen; return(u);int canmoveto(int row, int col, int *p, int *q, int direction) int r,c; r=row; c=col; switch(direction) case 0: c-; /左 break
17、; case 1: r+; /下 break; case 2: c+; /右 break; case 3: r-; /上 *p=r; *q=c; if(r=n|c=n) /如果越界返回0 return(0); if(arc=0) /如果是空格返回1 return(1); return(0); /其余情况返回0int isaim(int row, int col) if(row*n+col=t) return(1); else return(0);int used(int row, int col) if(arowcol=0) / 0表示空格 return(0); else return(1);
18、void addtoopen(int row, int col) int u; u=row*n+col; opentail+= u; tail=tail%openlen;void readdata() int i,j,row,col; char str20; 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;in;i+) gets(str); for(j=0;jn;j+) if(strj=.) aij=0; /0
19、表示空格 else aij=-2; /2表示墙 void init() head=0; tail=1; open0=s;测试数据如下:12 10 7 1 8XXXXXXXXXXXXX.X.XXXX.X.XX.XX.X.XX.XXX.XX.X.X.XX.XXXXXXXXXXX.X.X.XX.XXX.XXXXX.X.XXXX.XXXX.X.XXXXXXXX.XXXXXXXXXXXXXXX注:测试数据可在运行时粘贴上去(点击窗口最左上角按钮,在菜单中选则“编辑”/“粘贴”即可)。想一想:此程序都存在哪些问题,如果openlen太小程序会不会出错,加入代码使程序能自动报出此类错误。3. 跳马给一个20
20、0200的棋盘,问国际象棋的马从给定的起点到给定的终点最少需要几步。Sample Input 0 0 1 1 Sample output 4 状态:马所在的行、列。程序如下:#includevoid readdata(); /读入数据void init(); /初始化int search(); /广度优先搜索int emptyopen(); /判栈是否为空:空:1;非空:0。long takeoutofopen(); /从栈中取出一个元素,并把该元素从栈中删除int canmoveto(int,int,int*,int*,int); /判能否移动到该方向,并带回坐标(r,c)int isaim
21、(int row, int col); /判断该点是否是目标int used(int,int); /判断该点是否已经走过void addtoopen(int,int); /把该点加入到open表int a200200,n=200; /a存放棋盘,n为迷宫边长long open2000,head,tail,openlen=2000; /open表1367long s,t; /起点和终点int search() long u; int row, col, r, c, i, num; while(!emptyopen() /当栈非空 u=takeoutofopen(); /从栈中取出一个元素,并把该
22、元素从栈中删除 row=u/n; /计算该点所在的行 col=u%n; /计算该点所在的列 num=arowcol; /取得该点的步数 for(i=0;i8;i+) if(canmoveto(row,col,&r,&c,i) /判能否移动到该方向,并带回坐标(r,c) if(isaim(r,c) /如果是目标结点 return(num+1); /返回最小步数 if(!used(r,c) /如果(r,c)还未到达过 arc=num+1; /记录该点的最小步数 addtoopen(r,c); /把该点加入到open表 return -1;int main() /为了让search()显示在一页内和
23、main函数换了以下 /一般的算法程序main函数写在最上面读起来更方便 int number; readdata(); /读取数据 init(); /初始化 number=search(); /广搜并返回最小步数 printf(%d,number); /打印结果int emptyopen() if(head=tail) return(1); else return(0);long takeoutofopen() long u; if(head=tail) printf(errer: stack is empty); return(-1); u=openhead+; head=head%ope
24、nlen; return(u);int used(int row, int col) if(arowcol=0) return(0); else return(1);void addtoopen(int row, int col) int u; if(head-tail)%openlen=1) printf(open table overflow); u=row; u=u*n+col; opentail+= u; tail=tail%openlen;void readdata() long row,col; scanf(%ld%ld,&row,&col); /起点坐标 s=row*n+col; scanf(%ld%ld,&row,&col); /终点坐标 t=row*n+col;void init() head=0; tail=1; open0=s;int isaim(int row, int col) if(row*n+col=t) return(1); else return(0);思考:参考第4题,改为用结构体表示状态写此程序。4. 独轮车独轮车的轮子上有5种颜色,每走一格颜色变化一次,独轮车只能往前推,也可以在原地旋转,每走一格,需要一个单位的时
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1