POJ2488 A Knight's Journey
题目:http://poj.org/problem?id=2488
题目大意:可以从任意点开始,只要能走完棋盘所有点,并要求字典序最小,不可能的话就impossible;
思路:dfs+回溯,因为字典序最小,如果可以的话,肯定是从(1,1)开始的。然后递归搜索该点的所有方向,不能满足就回溯,直到找到能满足的,或者一直找不到。
代码+注释:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
bool vis[27][27];
int des[8][2] = {-2, -1, -2, 1, -1, -2, -1, 2, 1, -2, 1, 2, 2, -1, 2, 1};//八个方向
int T, n, m, tempx, tempy;
struct node{
int x;
int y;
}stu[27];
bool flag;
bool judge(int x, int y) {
if(x < 1 || x > n || y < 1 || y > m)
return false;
if(vis[x][y])
return false;
if(flag)
return false;
return true;
}
void dfs(int x, int y, int num) {
stu[num].x = x;
stu[num].y = y;
if(num == m * n) {//跑完所有的点了
flag = true;
return;//这里的return 不是直接出去,而是返回上一状态?我的理解
}
for(int i =0; i < 8; i++) {//遍历所有的方向
tempx = x + des[i][0];
tempy = y + des[i][1];
if(judge(tempx, tempy)) {//这个点满足条件
vis[tempx][tempy] = true;//标记访问过
dfs(tempx, tempy, num + 1);//继续搜索,点数+1
vis[tempx][tempy] = false;//说明该点虽然满足条件,但是无法走完全部的点,因此回溯
}
}
}
int main() {
scanf("%d", &T);
int j = 1;
while(T--) {
scanf("%d%d", &m, &n);
flag = false;
memset(vis, false, sizeof(vis));
vis[1][1] = true;//肯定是从第一个开始的(保证字典序最小)
dfs(1, 1, 1);// (1,1,第一个点)
printf("Scenario #%d:\n", j++);
if(flag) {
for(int i = 1; i <= n * m; i++) {
printf("%c%c", 'A' + stu[i].x - 1, '1' + stu[i].y - 1);
}
cout << endl;
} else cout << "impossible" << endl;
cout << endl;
}
}
埋骨何须桑梓地,人生无处不青山