算法分析与设计试验报告.docx
- 文档编号:10147265
- 上传时间:2023-02-08
- 格式:DOCX
- 页数:16
- 大小:112.90KB
算法分析与设计试验报告.docx
《算法分析与设计试验报告.docx》由会员分享,可在线阅读,更多相关《算法分析与设计试验报告.docx(16页珍藏版)》请在冰豆网上搜索。
算法分析与设计试验报告
中南大学
算法分析与设计
实验报告
学院:
_____
专业班级:
学号:
姓名:
指导教师:
2011年12月
实验一
实现求n皇后问题和子集和数问题的回溯算法
<一>n皇后问题
1、设计思想
(1)为解决这个问题,我们把棋盘的横坐标定为i,纵坐标定为j,i和j的取值范围是从1到8。
当某个皇后占了位置(i,j)时,在这个位置的垂直方向、水平方向和斜线方向都不能再放其它皇后了。
(2)为第i个皇后选择位置的算法如下:
for(j=1;j<=8;j++)/*第i个皇后在第j行*/
if((i,j)位置为空))/*即相应的三个数组的对应元素值为1*/
{占用位置(i,j)/*置相应的三个数组对应的元素值为0*/
ifi<8
为i+1个皇后选择合适的位置;
else输出一个解
}
intiStart,iEnd;
iStart=GetTickCount();//得到系统时间
nQueen(n);
iEnd=GetTickCount();//得到系统时间
cout<<"Itneed"< 总而言之,通过这次实验,我更加明白了回溯法的设计思想。 2、源代码: #include #include #include #include classQueen{ friendintnQueen(int); boolPlace(intk); voidBacktrack(intt); voidOutput(); intn,//皇后个数 longsum;//当前已找到的可行性方案数 }; boolQueen: : Place(intk){ for(intj=1;j if((abs(k-j)==abs(x[k]-x[j]))||(x[j]==x[k])){ returnfalse; } } returntrue; } voidQueen: : Backtrack(intt){ if(t>n){ sum++; Output(); } else{ for(inti=1;i<=n;i++){ x[t]=i; if(Place(t)){ Backtrack(t+1); } } } } intnQueen(intn){ QueenX; X.n=n; X.sum=0; int*p=newint[n+1]; for(inti=0;i<=n;i++){ p[i]=0; } X.x=p; X.Backtrack (1); delete[]p; returnX.sum; } voidQueen: : Output(){ cout<<"\n*****第"< cout<<"┌";//head行 for(intk=1;k cout<<"--┬"; cout<<"--┐\n"; for(inti=1;i<=n;i++){ cout<<"│"; for(intj=1;j<=x[i]-1;j++) cout<<"│"; cout<<"⊙",x[i]+1;cout<<"│"; for(intj=x[i];j<=n-1;j++) cout<<"│"; cout<<"\n"; if(i cout<<"├";//间行 for(intk=1;k cout<<"--┼"; cout<<"--┤\n"; } if(i>n-1){ cout<<"└";//end行 for(intp=1;p cout<<"--┴"; cout<<"--┘\n"; } } cout< } intmain(){ intn,m; cout<<"\n\n请输入皇后的个数: "; cin>>n; intiStart,iEnd; m=nQueen(n); cout<<"\n***"< } 运行截图: <二>1、子集和数问题的表示方案 本设计利用大小固定的元组来研究回溯算法,在此情况下,解向量的元素X(i)取1或0值,它表示是否包含了权数W(i).生成图中任一结点的儿子是很容易的。 对于i级上的一个结点,其左儿子对应于X(i)=1,右儿子对应于X(i)=0。 对于限界函数的一种简单选择是,当且仅当 时,B(X (1),···,X(k))=true。 显然,如果这个条件不满足,X (1),···,X(k)就不能导致一个答案结点。 如果假定这些W(i)一开始就是按非降次序列排列的,那么这些限界函数可以被强化。 在这种情况下,如果 则X (1),···,X(k)就不能导致一个答案结点。 因此,将要使用的限界函数是 B (X (1),···,X(k))=true,当且仅当 。 2主要数据类型与变量 intM;//表示要求得到的子集和; ints;//表示所选当前元素之前所选的元素和; intw[N];//存储原始集合的N个元素,根据问题实例初始化; intx[N];//变长表示的解向量,不进行初始化; 3算法或程序模块 #include #defineM31 #defineN4//集合元素个数 intw[N]={11,13,24,7}; intx[N]; voidSubset(ints,intk){//解子集和数问题函数 inti,l;l=0;x[l]=k; while(l>=0){ while(s+w[x[l]-1] s=s+w[x[l]-1]; k++;l++; x[l]=k; } while(s+w[x[l]-1]>M&&k<=N){ k++;x[l]=k; } if(s+w[x[l]-1]==M){ k++; for(i=0;i<=l;i++) printf("%d",x[i]);//输出变长解向量 printf("\n"); } while(k>N){//返回上一个节点,实现回溯的主要思想 l--;k=x[l];x[l]=k+1;s=0; for(i=0;i s=s+w[x[i]-1]; } } } } voidmain(){ Subset(0,1);//调用subset(ints,intk)函数 } 结果 <三>实验心得 第一个实验是在别人代码的基础上,结合自己对回溯算法的理解改的。 在最初的时候,遇到了很大的麻烦,毕竟是改的别人的代码,对代码的理解不是很透彻,出现了很多错误,但在同学们的帮助下,通过自己的一个下午加一个晚上的修改,终于调试成功。 这种列式使用大小固定的元组表示所有的解,得出一个问题的解可以有数种表示形式,而这些表示形式都是的所有的解是满足某些约束条件的多元组。 回溯算法通过系统的检索给定问题的解空间来确定问题的解。 这检索可以用这个解空间的树结构来简化。 对于一个给定的解空间,可能有多种树结构。 实验二 用动态规划的方法实现0/1背包问题 1.问题描述: 给定n种物品和一背包.物品i的重量是w[i],其价值为u[i],背包的容量为C.如何选择装入背包的物品,使得装入背包中物品的总价值最大。 2.问题分析及实现: 我们可以先几个数组量,分别是weight[i]表示物品i的重量,value[i]表示物品i的价值,result[i]存放结果,即存放0和1,0表示该物品没有被选,1表示该物品被选,m[amount][capacity]表示物品为i,i+1,i+2,...,n,容量为j时,背包的最大价值,则由动态规划的思想可得: 3.源代码; #include #include usingnamespacestd; voidKnapsack(intm[][11],int*v,int*w,intc,intn); voidTraceback(intm[][11],int*w,intc,intn,int*x); voidmain() { intwight[6]={0,2,2,6,5,4};//物品重量 intvalue[6]={0,6,3,5,4,6};//物品价值 intcapacity=10;//背包容量 intamount=5;//物品数量 intresult[6]={0,0,0,0,0,0};//存放结果 intm[6][11];//m数组: m[i][j]表示物品为i,i+1,i+2,...,n,容量为j时,背包的最大价值 for(inti=0;i<6;i++){ for(intj=0;j<11;j++){ m[i][j]=0; } } Knapsack(m,value,wight,capacity,amount);//生成m数组Traceback(m,wight,capacity,amount,result);//倒推出结果 cout<<"\n\ndown! "< getche(); } voidKnapsack(intm[][11],int*v,int*w,intc,intn){ intjMax=min(w[n]-1,c); for(intj=0;j<=jMax;j++)m[n][j]=0; for(intj=w[n];j<=c;j++)m[n][j]=v[n]; for(inti=n-1;i>1;i--){ intjMax=min(w[i]-1,c); for(intj=0;j<=jMax;j++)m[i][j]=m[i+1][j]; for(intj=w[i];j<=c;j++)m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]); } if(c>=w[1])m[1][c]=max(m[2][c],m[2][c-w[1]]+v[1]); elsem[1][c]=m[2][c]; } voidTraceback(intm[][11],int*w,intc,intn,int*x){ for(inti=1;i if(m[i][c]==m[i+1][c]) x[i]=0; else{ x[i]=1; c=c-w[i]; } x[n]=(m[n][c]>0? 1: 0); } cout<<"m[1][10]="< for(inti=1;i<6;i++){ cout< } } 测试数据: N=5,C=10,w={2,2,6,5,4},v={6,3,5,4,6} 测试结果: m[1][10]=15 选择: 11001 用户结果屏幕: 实验三 用分支限界法实现0/1背包问题 1.设计原理 对于每一个物品i,对于该物品只有选与不选2个决策,总共有n个物品,可以顺序依次考虑每个物品,这样就形成了一棵解空间树: 基本思想就是遍历这棵树,以枚举所有情况,最后进行判断,如果重量不超过背包容量,且价值最大的话,该方案就是最后的答案。 2.主代码为: K.Backtrack (1); delete[]Q; delete[]K.w; delete[]K.p; if((fp=fopen("output.txt","w"))==NULL) { fprintf(stderr,"Cannotopeninputfile.\n"); exit(0); } fprintf(fp,"%d,%d,%d,%d",K.x[4],K.x[1],K.x[2],K.x[3]); fclose(fp); cout<<"当前最优装配: "; cout< for(i=1;i { cout<<""< } cout< } template voidKnap : Backtrack(inti) { if(i>n){ bestp=cp; return; } if(cw+w[i]<=c){ x[i]=1; cw+=w[i]; cp+=p[i]; Backtrack(i+1); cw-=w[i]; cp-=p[i]; } if(Bound(i+1)>bestp) x[i]=0; Backtrack(i+1); } template TypepKnap : Bound(inti) {//计算上界 Typewcleft=c-cw;//剩余容量 Typepb=cp; //以物品单位重量价值递减序装入物品 while(i<=n&&w[i]<=cleft){ cleft-=w[i]; b+=p[i]; i++; } //装满背包 if(i<=n)b+=p[i]/w[i]*cleft; returnb; 运行截图为 : 实验四 要求: 用深度优化的方法遍历一个图,并判断图中是否有回路存在,如果有,请输出回路
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 分析 设计 试验报告
![提示](https://static.bdocx.com/images/bang_tan.gif)