题目
- 马踏棋盘算法,即骑士周游问题。
- 将马放在国际象棋的 8×8 棋盘的某个方格中,马按走棋规则(马走日字)进行移动。
- 每个方格只进入一次,走遍棋盘上全部 64 个方格。
回溯问题模型
特征
- 解组织成树的形式
- 从根节点开始进行深度优先遍历
- 访问节点时进行判断,是否符合条件,符合就继续,否则进行回溯,此节点后的都不用访问(与暴力算法的区别,降低算法复杂度)
模型
代码
- 代码演示的是5*5的棋盘。
- 递归的出口为步数k=棋盘数M*M。
- 递归主函数就是对每一坐标的8种走法进行判断。符合条件就调用递归函数。
- 然后回溯上一步。
- map变量ma记录棋盘上的每一个坐标是否走过。没有走过的,将其坐标加入map中,成为键,值记录第几步。
#include<iostream>
#include<map>
#include<iomanip>
using namespace std;
struct Pos{
int x;
int y;
Pos(int x,int y){
this->x=x;
this->y=y;
}
};
int count=0;
void show(int M,map<Pos,int>& ma);
Pos delta[]={Pos(-1,2),Pos(-1,-2),Pos(1,2),Pos(1,-2),
Pos(2,1),Pos(2,-1),Pos(-2,1),Pos(-2,-1)};
Pos operator+(Pos a,Pos b){
return Pos(a.x+b.x,a.y+b.y);
}
bool outOfBounds(int M,Pos p){
if(p.x<0 || p.x>= M) return true;
if(p.y<0 || p.y>= M) return true;
return false;
}
bool operator< (Pos a,Pos b){
if(a.x != b.x) return a.x < b.x;
return a.y < b.y;
}
bool f(int M,map<Pos,int>& ma,Pos p,int k){
if(k==M*M){
++count;
cout<< count<<endl;
show(M,ma);
return true;
}
for(int i=0;i<8;i++){
Pos p1=p+delta[i];
if(outOfBounds(M,p1)) continue;
if(ma.count(p1)) continue;
ma[p1] = k+1;
f(M,ma,p1,k+1);
ma.erase(p1);
}
return false;
}
void show(int M,map<Pos,int>& ma){
for(int i=0;i<M;i++){
for(int j=0;j<M;j++){
cout <<setw(3)<<ma[Pos(i,j)];
}
cout<<endl;
}
cout<<"********************"<<endl;
}
void horse(int M){
map<Pos,int> ma;
Pos p(0,0);
ma[p]=1;
f(M,ma,p,1);
}
int main(){
horse(5);
cout<<"总共有:"<<count<<"种走法";
return 0;
}