回溯与分支限界算法设计.docx
- 文档编号:7826095
- 上传时间:2023-01-26
- 格式:DOCX
- 页数:16
- 大小:33.12KB
回溯与分支限界算法设计.docx
《回溯与分支限界算法设计.docx》由会员分享,可在线阅读,更多相关《回溯与分支限界算法设计.docx(16页珍藏版)》请在冰豆网上搜索。
回溯与分支限界算法设计
算法设计与分析实验报告
专业
班级
姓名
学号
实验名称
实验四:
回溯与分支限界算法设计
实验目的
1.掌握回溯法解决问题的一般步骤。
2.学会使用回溯法解决实际问题。
3.掌握分支限界法解决问题的基本思想。
4.学会使用分支限界法解决实际问题。
实验内容
1.骑士游历问题(采用回溯法):
在国际象棋的棋盘(8行×8列)上放置一个马,按照“马走日字”的规则,马要遍历棋盘,即到达棋盘上的每一格,并且每格只到达一次。
若给定起始位置(x0,y0),编程探索出一条路径,沿着这条路径马能遍历棋盘上的所有单元格。
2.行列变换问题(采用分支限界法):
给定两个mn方格阵列组成的图形A和图形B,每个方格的颜色为黑色或白色,如下图所示。
行列变换问题的每一步变换可以交换任意2行或2列方格的颜色,或者将某行或某列颠倒。
上述每次变换算作一步。
试设计一个算法,计算最少需要多少步,才能将图形A变换为图形B。
算法描述
1.骑士游历问题的解题思路或算法思想:
如果在每步选择方向时,不是任意选择一个方向,而是经过一定的测试和计算,“预见”每条路的“宽窄”,再选择一条最“窄”的路先走,成功的可能性较大。
理由是先走“困难的路”,光明大道留在后面。
因为每一格迟早都要走到,与其把困难留在后面,不如先走“困难的路”,这样路就会越走越宽,成功的机会就越大。
这种方法称为预见算法。
为每个方向测定一个值――可通路数,它表示该位置上还有多少条通路。
在每一格上对8个方向都进行试探,并分析比较,下一步应该选择可通路数值最小的方向走。
2.行列变换问题的解题思路或算法思想:
先进先出队列式分支限界法
输入数据,将计算出的最少变换次数和相应的变换序列输出。
第1行是最少变换次数。
从第2行开始,每行用4个数表示一次变换。
程序及运行结果
1.骑士游历问题的程序:
packagecom.t5;
importjava.util.Scanner;
publicclassQishi{
privatebooleanTravel(intfirstX,intfirstY,int[][]board){
//对应骑士可走的8个方向
int[]movex={-2,-1,1,2,2,1,-1,-2};
int[]movey={1,2,2,1,-1,-2,-2,-1};
//下一步出路的位置
int[]nextStepX=newint[board.length];
int[]nextStepY=newint[board.length];
//记录出路的个数
int[]exitS=newint[board.length];
intnextX=firstX;
intnextY=firstY;
board[nextX][nextY]=1;
for(intm=2;m<=Math.pow(board.length,2);m++){
//初始化下一个位置可走的位置的数目
for(inti=0;i exitS[i]=0; } intcount=0; //试探8个方向 for(inti=0;i<8;i++){ inttemI=nextX+movex[i]; inttemJ=nextY+movey[i]; //走到边界,路断 if(temI<0||temI>7||temJ<0||temJ>7){ continue; } //记录下可走的方向 if(0==board[temI][temJ]){ nextStepX[count]=temI; nextStepY[count]=temJ; count++; } } //到这里,cout表示当前点有几种走法。 nextStep中存储各种走法的坐标。 intmin=-1; if(count==0){ returnfalse; } if(1==count){ min=0; }else{ for(inti=0;i for(intj=0;j<8;j++) { inttemI=nextStepX[i]+movex[j]; inttemJ=nextStepY[i]+movey[j]; if(temI<0||temI>7||temJ<0||temJ>7){ continue; } //记录下这个位置可走的方向数 if(0==board[temI][temJ]){ exitS[i]++; } } } inttem=exitS[0]; min=0; //从可走的方向中,寻找最少走的出路 for(inti=1;i if(tem>exitS[i]){ tem=exitS[i]; min=i; } } } //得到最少的出路 nextX=nextStepX[min]; nextY=nextStepY[min]; board[nextX][nextY]=m; } returntrue; } publicstaticvoidmain(String[]args){ intfirstX,firstY; System.out.println("输入起始点(0-7): "); Scannerscanner=newScanner(System.in); firstX=scanner.nextInt(); firstY=scanner.nextInt(); int[][]board=newint[8][8]; Qishiknight=newQishi(); if(knight.Travel(firstX,firstY,board)){ System.out.println("游历完成: "); }else{ System.out.println("游历失败! \n"); } for(inti=0;i for(intj=0;j if(board[i][j]<10){ System.out.print(""+board[i][j]); }else{ System.out.print(board[i][j]); } System.out.print(""); } System.out.println(); } } } 实例: 2.行列变换问题的程序: packagecom.t8; importjava.util.LinkedList; importjava.util.Scanner; classgraph{ staticintsour,dest;//sour是图形的初始整数,dest是图形的目的整数 staticintans[]=newint[1<<16];//静态变量(即全局变量),用于存放图形变换的路径 intm=4,n=4,x; introw[]=newint[4]; intcol[]=newint[4]; voidsetx(intx){ this.x=x; } intgetx(){ returnthis.x; } voidrowx(){//将一个整数划分成四行二进制 inty; for(inti=0;i y=1; row[i]=0; for(intj=0;j if((x&1)! =0)//如果x的最低位是1 row[i]|=y; y<<=1; x>>=1; } } } voidcolx(){//将一个整数划分成四列二进制 inty; for(intj=0;j y=1; for(inti=0;i for(intj=0;j if((x&1)! =0)//如果x的最低位是1 col[j]|=y; x>>=1; } y<<=1; } } voidrowy(){//将四行二进制转换成一个整数 intz=1,x=0,y; for(inti=0;i y=row[i]; for(intj=0;j if((y&1)! =0)//如果y的最低位是1 x|=z; z<<=1; y>>=1; } } this.x=x; } voidcoly(){//将四列二进制转换成一个整数 intz=1,x=0,y; for(inti=0;i for(intj=0;j if((col[j]&1)! =0)//如果y的最低位是1 x|=z; z<<=1; col[j]>>=1; } } this.x=x; } voidSwaprow(inti,intj){//将二进数进行行互换 into; o=row[i]; row[i]=row[j]; row[j]=o; } voidSwapcol(inti,intj){//将二进数进行列互换 into; o=col[i]; col[i]=col[j]; col[j]=o; } voidreveR(intk){//将二进数进行行颠倒 inty=0,z=1<<(4-1); for(intj=0;j<4;j++){ if((row[k]&1)! =0)//如果y的最低位是1 y|=z; z>>=1; row[k]>>=1; } row[k]=y; } voidreveC(intk){//将二进数进行列颠倒 inty=0,z=1<<(4-1); for(intj=0;j<4;j++){ if((col[k]&1)! =0)//如果y的最低位是1 y|=z; z>>=1; col[k]>>=1; } col[k]=y; } introwswap(intx,inti,intj){//将二进制数的第i行与第j行互换 this.x=x; rowx(); Swaprow(i,j); rowy(); returnthis.x; } intcolswap(intx,inti,intj){//将二进制数的第i列与第j列互换 this.x=x; colx(); Swapcol(i,j); coly(); returnthis.x; } intrevrow(intx,intk){//将二进制数的第K行颠倒 this.x=x; rowx(); reveR(k); rowy(); returnthis.x; } intrevcol(intx,intk){//将二进制数的第K列颠倒 this.x=x; colx(); reveC(k); coly(); returnthis.x; } } publicclassTuxing{ publicstaticvoidmain(String[]args){ finalintMaxsize=1<<16; graphgN;//用于进行行变换、列变换、行颠倒、列颠倒 intE,N;//变换前的初始值,变换前的结果值 gN=newgraph(); inthash[]=newint[1<<16]; inti,j,h=0;charc; graphG1=newgraph(); //初始化,输入初始值和目标值,即1010010000101010和1010000001100101 Scannerscanner=newScanner(System.in); Stringss=scanner.nextLine(); char[]chArrs=ss.toCharArray(); for(graph.sour=i=0;i<16;i++){ c=chArrs[i]; graph.sour|=(int)(c-'0')< } Stringsd=scanner.nextLine(); char[]chArrd=sd.toCharArray(); for(graph.dest=i=0;i<16;i++){ c=chArrd[i]; graph.dest|=(int)(c-'0')< } LinkedListqueue=newLinkedList();//初始化先进先出队列 for(intk=0;k G1.x=graph.sour; hash[G1.x]=0; queue.add(G1.x); while(! queue.isEmpty()){//以先进先出队列式实现分支限界法 E=(int)queue.removeFirst(); for(i=0;i<4-1;i++){//行变换 for(j=i+1;j<4;j++){ gN.x=gN.rowswap(E,i,j); N=gN.x; if(hash[N]==-1){ hash[N]=hash[E]+1; graph.ans[N]=E; queue.add(N); } } } for(i=0;i<4-1;i++){//列变换 for(j=i+1;j<4;j++){ gN.x=gN.colswap(E,i,j); N=gN.x; if(hash[N]==-1){ hash[N]=hash[E]+1; graph.ans[N]=E; queue.add(N); } } } for(i=0;i<4;i++){//行颠倒 gN.x=gN.revrow(E,i); N=gN.x; if(hash[N]==-1){ hash[N]=hash[E]+1; graph.ans[N]=E; queue.add(N); } } for(i=0;i<4;i++){//列颠倒 gN.x=gN.revcol(E,i); N=gN.x; if(hash[N]==-1){ hash[N]=hash[E]+1; graph.ans[N]=E; queue.add(N); } } if(hash[graph.dest]! =-1){//如果目的值被遍历到,则退出循环 System.out.println("OK");break; } } System.out.println(hash[graph.dest]); output(graph.dest);//输出变换的路径 } publicstaticvoidoutb(intx){//将一个整数以四行二进制的形式显示 for(inti=0;i<4;i++){ for(intj=0;j<4;j++){ if((x&1)! =0)System.out.print (1); elseSystem.out.print(0); x/=2; } System.out.println(); } } publicstaticvoidoutput(intN){ if(N==graph.sour){ System.out.println(); outb(N); return; } output(graph.ans[N]);//graph.ans[N]存放着从初始值到目的值的遍历路径 System.out.println(); outb(N); } } 实例: 总结 实验心得体会: 掌握回溯法解决问题的一般步骤。 学会使用回溯法解决实际问题。 掌握分支限界法解决问题的基本思想。 学会使用分支限界法解决实际问题 改进意见: 对于分支限界法了解的不透彻,应与老师沟通解决此问题,回溯法可以帮我们更好的解决一些多解的复杂性问题,所以,要更好的去学习和运用回溯法思想。 实验成绩: 指导教师: 年月日
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 回溯 分支 限界 算法 设计