您的位置:首页 > 理论基础 > 数据结构算法

数据结构经典算法(7)骑士走棋盘

2014-03-25 16:34 579 查看
说明:骑士旅游(Knighttour)在十八世纪初倍受数学家与拼图迷的注意,它什么时候被提出
已不可考,骑士的走法为西洋棋的走法,骑士可以由任一个位置出发,它要如何走完[所有的位 置?
解法:骑士的走法,基本上可以使用递回来解决,但是纯綷的递回在维度大时相当没有效率,
 一个聪明的解法由J .C. Warnsdorff在1823年提出,简单的说,先将最难的位置走完,接下来的路 就宽广了,骑士所要走的下一步,「为下一步再选择时,所能走的步数最少的一步。 」 个,使用这 方法,在不使用递回的情况下,可以有较高的机率找出走法(找不到走法的机会也是有的) 。
 #include <iostream>
#include <iomanip>
#define SIZE 8
using namespace std;
bool travel(int board[][SIZE],int x,int y);
int possible(int board[][SIZE],int *nexti,int *nextj,int x,int y);
int min(int board[][SIZE],int *nexti,int *nextj,int count);
void printBoard(int borad[][SIZE]);
int main()
{
int start_x;
int start_y;
cout<<"输入初始位置"<<endl;
cin>>start_x>>start_y;
int board[SIZE][SIZE]={0};
if(travel(board,start_x,start_y))cout<<"遍历成功!"<<endl;
else cout<<"遍历失败!"<<endl;
printBoard(board);
}
bool travel(int board[][SIZE],int x,int y)
{
board[x][y]=1; //当前位置为第1次走的位置
int nexti[SIZE]={0};
int nextj[SIZE]={0}; //下一跳初始化
int i=x;
int j=y;
int MAX=SIZE*SIZE;
int count=0;
for(int m=2;m<=MAX;m++) //遍历棋盘
{
count=possible(board,nexti,nextj,i,j);//得到可能的下一跳数目
if(count==0)return false; //无可走方向,遍历失败
int min_Direction=min(board,nexti,nextj,count);//在多个可能方向中查找下一跳方向最少的方向
i=nexti[min_Direction]; //下一跳位置坐标
j=nextj[min_Direction];
board[i][j]=m; //当前位置为第m次走的位置
}
return true;
}
int possible(int board[][SIZE],int *nexti,int *nextj,int x,int y)
{
int mvi[SIZE]={-2,-1,1,2,2,1,-1,-2}; //下一跳可能的八个方向(x坐标y坐标)
int mvj[SIZE]={1,2,2,1,-1,-2,-2,-1};
int count=0;
for(int i=0;i<SIZE;++i)
{
int tmpx=x+mvi[i];
int tmpy=y+mvj[i];
if(tmpx<0||tmpy<0||tmpx>SIZE-1||tmpy>SIZE-1)continue; //越界,不是可行方向
if(board[tmpx][tmpy]==0) //未走过,找到一个可能方向
{
nexti[count]=tmpx;
nextj[count]=tmpy;
count++;
}
}
return count; //返回可能的方向数
}
int min(int board[][SIZE],int *nexti,int *nextj,int count)
{
int mvx[SIZE]={-2,-1,1,2,2,1,-1,-2};
int mvy[SIZE]={1,2,2,1,-1,-2,-2,-1};
int exist[SIZE]={0}; //记录该方向的下一跳方向的数目
int min_direction=-1; //初始化最小方向数的方向
if(count==1)min_direction=0; //只有一个可行方向
else
{
for(int i=0;i<count;++i) //在所有可行方向中遍历
{
for(int j=0;j<SIZE;++j) //计算每一个方向下一跳的数目
{
int tmpx=nexti[i]+mvx[j];
int tmpy=nextj[i]+mvy[j];
if(tmpx<0||tmpy<0||tmpx>SIZE-1||tmpy>SIZE-1)continue;
if(board[tmpx][tmpy]==0)
{
exist[i]++;
}
}
}
int min=exist[0]; //取其中最小数目的方向
min_direction=0;
for(int i=1;i<count;++i) //此处count开始错为SIZE,一直未查出错误
//exist数组只有count位不为0
{
if(exist[i]<min)
{
min=exist[i];
min_direction=i;
}
}
}
return min_direction;
}
void printBoard(int board[][SIZE])
{
for(int i=0;i<SIZE;++i)
{
for(int j=0;j<SIZE;++j)
{
cout<<setw(2)<<board[i][j]<<" ";
}
cout<<endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息