1.问题:在n*m的棋盘中,马只能走“日” 字。马从位置(x,y)处出发,把棋盘的每一格都走一次,且只走一次。找出所有路径。
2.设计思路:马在每一个位置有八种走法如下图,搜索空间是n*m(二维数组的大小),使用dep代表此位置是第几次被遍历(被马第几次走过);递归遍历解空间树,如果满足退出条件,也就是dep==n*m(遍历完整个数组的所有元素,每个格子走一遍);如果不满足退出条件,那就以新的节点为起始位置,继续调用函数去遍历解空间树。最后输出结果。
3.代码:
/*回溯法之马的遍历*/
#include<stdio.h>
void find(int x,int y,int dep);
void output(); //输出解空间树
int check(int,int); //检查坐标是否出界,是否已走
int n=5,m=4;
int fx[8]={1,2,2,1,-1,-2,-2,-1},fy[8]={2,1,-1,-2,-2,-1,1,2}; //马遍历时x,y的轴增量
int a[5][4]; //数组的大小
int dep,x,y,count;
int main()
{
int i,j;
count=0;
dep=1;
printf("请输入x y的坐标: ");
scanf("%d%d",&x,&y);
if (x>=n||y>=m||x<0||y<0)
{
printf("输入的坐标有误,请重新输入:\n");
scanf("%d%d",&x,&y);
}
for(i=0;i<n;i++)
for(j=0;j<m;j++)
a[i][j]=0;
a[x][y]=1;
find(x,y,2);
if(count==0)
printf("No solution!\n");
else
printf("count=%d",count);
return 0;
}
void find(int x,int y,int dep) //遍历解空间树
{
int i,xx,yy;
for(i=0;i<8;i++)
{
xx=x+fx[i]; //加上方向增量,形成新的坐标
yy=y+fy[i];
if(check(xx,yy)==1) //判断新坐标是否出界,是否已走
{
a[xx][yy]=dep; //走向新的坐标
if(dep==n*m)
output(); //输出一个解空间树
else
find(xx,yy,dep+1);//从新坐标出发,递归下一层
a[xx][yy]=0;
}
}
//回溯,恢复未走标志
}
void output()
{
count++;
printf("\ncount=%d",count);
for(y=0;y<n;y++)
{
printf("\n");
for(x=0;x<m;x++)
printf("%3d ",a[y][x]);
}
printf("\n");
}
int check(int x,int y)
{
if(x>=0&&x<n&&y>=0&&y<m&&a[x][y]==0) //检查坐标是否出界,是否已走
return 1;
else
return 0;
}
4.运行结果: