问题很常见喽,也成为骑士巡逻问题。中国象棋中“马走日“,现在有一匹马和一个8X8的棋盘,在棋盘中任意位置。试着求解出一种方案,让这匹马遍历棋盘中的每一个节点,每个节点只能访问一次。
很明显是一个回溯的题目,不过最关键的部分就是优化了。我一开始用了穷举的方式。不过计算量实在太大了,计算机跑了一上午都没有算出来。后来查资料才知道有一种优化的方法,也称为Warnsdorff规则,具体就是:Warnsdorff规则指在所有可走且未经过的方格中,马只可能走这样一个方格:从该方格出发,马能跳的方格数最少;如果可跳的方格数相等,则从当前位置看,方格序号小的优先。依照这一规则往往可以找到一条路径但是并不一定能够成功。
也就是说,举例来说,如果马A从当前位置出发可以到达且合法的节点有3个,分别是B,C,D。同时从B,C,D出发可以到达且合法的节点分别为1,4,2个。则我们就选择B点,这就是上面Warnsdorff原则的含义。下面我给出一个简单的代码实现:
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
#define N 8
const int step[8][2]={{1,2},{2,1},{1,-2},{2,-1},{-1,2},{-2,1},{-1,-2},{-2,-1}};
class Pos{
public:
int x,y;
Pos(int _x,int _y):x(_x),y(_y){};
};
bool visited[N][N];
bool check(int x,int y){
if(x>=0 && x<N && y>=0 && y<N && visited[x][y]==false)
return true;
return false;
}
vector<Pos> ivec;
//计算当前点的可落子位置
int exitn(int x,int y,int a[]){
int count,xx,yy,k;
for(k=0,count=k;k<N;k++){
xx=x+step[k][0];
yy=y+step[k][1];
if(check(xx,yy))
a[count++]=k;
}
return count;
}
int select_min_pos(int x,int y){
int arr[N],count=exitn(x,y,arr),pos,b[N];
if(count==0)
return -1;
int min,k;
for(min=8,k=0;k<count;k++){
int temp=exitn(x+step[arr[k]][0],y+step[arr[k]][1],b);
if(temp<min){
min=temp;
pos=arr[k];
}
}
return pos;
}
void print(){
int i=1;
for(auto it=ivec.begin();it!=ivec.end();it++)
cout<<"第"<<i++<<"步"<<"("<<(*it).x<<","<<(*it).y<<")"<<endl;
}
int main(void){
int start_x,start_y;
cout<<"请输入马的起始位置: ";
while(1){
cin>>start_x>>start_y;
if(!check(start_x,start_y))
cout<<"输入错误,清重新输入."<<endl;
else
break; }
memset(visited,sizeof(bool)*N*N,0);
visited[start_x][start_y]=true;
int move=1,flag;
Pos v(start_x,start_y);
ivec.push_back(v);
for(move=2;move<=N*N;move++){
if((flag=select_min_pos(start_x,start_y))==-1)
break;
start_x=start_x+step[flag][0];
start_y=start_y+step[flag][1];
visited[start_x][start_y]=true;
Pos v(start_x,start_y);
ivec.push_back(v);
}
if(move>=64)
cout<<"Yeah we found a way to scan this chess"<<endl;
print();
return 0;
}
以上就是简单的实现。
参考资料:
http://zh.wikipedia.org/wiki/%E9%A8%8E%E5%A3%AB%E5%B7%A1%E9%82%8F
http://blog.csdn.net/xuguangsoft/article/details/8093140
感谢:SimonS