马的遍历问题:在n*m的棋盘上,马只能走日字。马从位置(x,y)处出发,把棋盘的每一点都走一次,且只走一次,找出所有路径。
问题分析:行n,列m,马在不出边界的情况下有8个方向可以行走(走日字),如当前坐标为(x,y),则行走后的坐标可以为:
(x+1,y+2) (x+1,y-2), (x+2,y+1) (x+2,y-1)
(x-1,y-2) (x-1,y+2) (x-2,y-1) (x-2,y+1)
回溯法算法设计: 搜索空间是n*M个点,约束条件是不出边界且每个点只经过一次,节点的扩展规则如上所述。
搜索过程是从任一点(x,y)出发,按深度优先原则,从8个方向尝试一个可以走的点,直到走过n*m个点。用递归容易实现。
注意:问题要求找出所有可能的解。就要注意回溯过程的清理现场工作,就是置当前位置为未经过。
数据结构设计:用一个变量dep记录递归深度,也就是走过的点数。当dep=n*m;找到一组解。
用n*m的二维数组记录马走过的过程,初始值为0表示未经过,起点存储的是1,终点存储的是n*m。
#include<iostream> using namespace std; void output(); int n=5,m=4; int fx[8]={1,2,2,1,-1,-2,-2,-1}; int fy[8]={2,1,-1,-2,-2,-1,1,2}; int a[5][4]; //下标从1开始 int dep,x,y,count; bool check(int x,int y) { if(x>=1&&x<=n&&y>=1&&y<=m&&(!a[x][y])) return true; else return false; } void find(int x,int y,int dep) { int i,xx,yy; for(i=1;i<=8;i++) //加上方向增量,形成新的坐标 { xx=x+fx[i]; yy=y+fy[i]; if(check(xx,yy)) //判断新坐标是否出界,是否已走过 { a[xx][yy]=dep; if(dep==n*m) output(); else find(xx,yy,dep+1); a[xx][yy]=0; //回溯,恢复未走未走 } } } void output() { count++; cout<<"\n"; cout<<"count="<<count; for(y=1;y<=n;y++) { cout<<endl; for(x=1;x<=m;x++) cout<<a[y][x]<<ends; } } int main() { int i,j; count=0; dep=1; cout<<"please input x,y"; cin>>x>>y; if(x>n||y>m||x<1||y<1) { cout<<"input error"; return -1; } for(i=1;i<=n;i++) for(j=1;j<=m;j++) a[i][j]=0; a[x][y]=1; find(x,y,2); if(count==0) cout<<"no solution!"; else cout<<"nambers of solution="<<count<<endl; }
代码输出好像有错误。