题目链接:A Knight’s Jounery
题目大意:
骑士按照“日”字规则行走,找一条能够让骑士遍历棋盘上所有点的路径,骑士可以在任何一块方块上开始和结束。要求在所有可行的路径中输出字母表排序最小的那个解。
样例输入:
第一行为样例个数,其余每一行为棋盘大小。
3
1 1
2 3
4 3
样例输出:
Scenario #1:
A1
Scenario #2:
impossible
Scenario #3:
A1B3C1A2B4C2A3B1C3A4B2C4
分析
并不是求最优解,而是判定是否存在一条符合条件的路径,所以使用深度优先搜索来达到这个目的。
搜索状态三元组(x,y,step)。目标状态(x,y,step),其中step = x*y。因为是按照日字型形状走,所以当前状态可以扩展出八个状态,当然,这些状态要按照字典序的顺序来安排。
宽度优先搜索使用队列实现先进先出,深度优先搜索使用递归来实现早得到的状态后得到扩展。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 30;
int p,q; //棋盘的大小
bool visit[MAXN][MAXN]; //判断上一个路径上的点是否访问过,避免重复访问。
int direction[8][2] = {
{-1,-2},{1,-2},{-2,-1},{2,-1},{-2,1},{2,1},{-1,2},{1,2}
}; //这里的状态分布式按照字典序的规则走的,比如A2 <B1
bool DFS(int x,int y,int step,string ans)
{
if(step == p * q){
cout<<ans<<endl<<endl;
return true;
}else {
for(int i = 0 ; i < 8; i++){
int nx = x + direction[i][0]; //坐标
int ny = y + direction[i][1];
char col = ny + 'A'; //输出路线
char row = nx + '1';
if(nx<0 || nx >= p||ny < 0|| ny >= q || visit[nx][ny]){
continue; //状态不合法,就不做任何操作。
}
visit[nx][ny] = true; //注意是判断完后再访问。
if(DFS(nx,ny,step+1,ans+col+row)){
return true;
}
visit[nx][ny] = false; //因为有路径 开始判断下一条路径了。。。
}
}
return false;
}
int main()
{
int n;cin>>n;
int CaseNumber = 0;
while(n--){
cin>>p>>q;
memset(visit,false,sizeof(visit));
cout<<"Scenario #"<<++CaseNumber<<":"<<endl;
visit[0][0] = true;
if(!DFS(0,0,1,"A1")){
cout<<"impossible"<<endl<<endl;
}
}
}
深度优先搜索,从一个状态一直访问其子状态,当符合条件后,就输出。若子状态不符合条件,转而判断上一层。