骑士旅游(Knight tour)在十八世纪初倍受数学家与拼图迷的注意,它什么时候被提出已不可考,骑士的走法为西洋棋的走法,骑士可以由任一个位置出发,它要如何走完所有有的位置?
算法描述:假设骑士所在当前位置八个方向x,y坐标分别为{-2,-1,1,2,2,1,-1,-2},{1,2,2,1,-1,-2,-2,-1}。遍历选择八个方向中下一个可走方向,选择下一个方向中可走步数最少的方向继续走。简单的说,先将最难的位置走完,接下来的路就宽广了,骑士所要走的下一步,为下一步再选择时,所能走的步数最少的一步。
/*
* 骑士走棋盘问题
* 算法描述:假设骑士所在当前位置八个方向x,y坐标分别为{-2,-1,1,2,2,1,-1,-2},{1,2,2,1,-1,-2,-2,-1}
* 遍历选择八个方向中下一个可走方向,选择下一个方向中可走步数最少的方向继续走。
* 简单的说,先将最难的位置走完,接下来的路
* 就宽广了,骑士所要走的下一步,为下一步再选择时,所能走的步数最少的一步。
*/
#include <stdio.h>
int pan[8][8]={0};
int travel(int pan[8][8],int x,int y)
{
int i,j,m;
int curX,curY;
int tempi,tempj;
int xx[8]={-2,-1,1,2,2,1,-1,-2},yy[8]={1,2,2,1,-1,-2,-2,-1};
int next[8]={0};
int min,minI,count;
int endX,endY;
//当前的x,y坐标
curX=x,curY=y;
//将当前位置设为1
pan[curX][curY]=1;
for(m=2;m<=64;m++)
{
//依次寻找马周围的八个位置是否可行
for(i=0;i<8;i++)
{
count=-1;
tempi=curX+xx[i];
tempj=curY+yy[i];
//不行则执行下一次循环寻找下一个位置
if(tempi<0||tempi>7||tempj<0||tempj>7||pan[tempi][tempj]!=0)
{
continue;
}
else
{
endX=tempi;
endY=tempj;
for(j=0;j<8;j++)
{
if(tempi+xx[j]<0||tempi+xx[j]>7||tempj+yy[j]<0||tempj+yy[j]>7||pan[tempi+xx[j]][tempj+yy[j]]!=0)
{
continue;
}
else
{
next[i]++;
}
}
}
}
minI=-1,min=8;
for(i=0;i<8;i++)
{
if(next[i]==0)
{
continue;
}
else if(min>next[i])
{
min=next[i];
minI=i;
}
next[i]=0;
}
if(minI==-1&&m!=64)
{
return 0;
}
else if(minI==-1&&m==64)
{
pan[endX][endY]=m;
return 1;
}
else
{
curX+=xx[minI];
curY+=yy[minI];
pan[curX][curY]=m;
}
}
return 1;
}
void display(int pan[8][8])
{
int i,j;
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
printf("%3d",pan[i][j]);
}
printf("\n");
}
}
int main()
{
int x,y;
display(pan);
printf("Enter start (x,y):");
scanf("%d%d",&x,&y);
if(travel(pan,x,y))
display(pan);
else
printf("不能走完!\n");
return 0;
}