这道棋盘题还是挺经典的,问题在于被一个新奇点子卡住好久。
本质上,这道题是一个棋盘中的哈密顿链路问题,这道题一个很经典的优化思路(很多人尝试,都A了),整个棋盘是否存在哈密顿链路,取决于A1是否存在(因为这道题要求的字典序,所以从这里开始找到一定是最优解),但是问题在于,如何将整个图的哈密顿链路存在性与特殊点A1结合是有待商榷的。很多人说的思路很显然是有漏洞的,认为只要有解,必定经过A1,那么可以让A1先到这个点的说法是错误的,这样怎么保证每个点只经过一次呢?此外,将棋盘染色,马的走法决定他的颜色不断变化,有些观点认为,只要一个点可以找到解,那么其他点都可以,这是错误的(可以自己思考),不过如果有解,那也一定是在于A1同色的格子有解
不过代码本质就是为了AC,也许这是对的,只是笔者水平有限,没有想出好的证明。题目也还是使用了朴素方法,每个格子搜一遍,复杂度倒不会太大,此外goto语句纯粹是为了用着方便,不建议
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxs= 11;
struct Node
{
int x, y;
Node(int _x= 0, int _y= 0) : x(_x), y(_y) {}
};
int p, q;
stack<Node> sol;
bool ins[maxs][maxs];
int step[8][2]= {{-2, -1}, {-2, 1} ,{-1, -2}, {-1, 2}, {1, -2}, {1, 2}, {2, -1}, {2, 1}};
void PrintAns(const int ok, const int sn)
{
printf("Scenario #%d:\n", sn);
if (!ok){
printf("impossible\n\n");
}
else{
Node cur;
while (!sol.empty()){
cur= sol.top();
sol.pop();
putchar('A'+cur.x-1);
printf("%d", cur.y);
}
putchar('\n');
putchar('\n');
}
}
int DFS(const int x, const int y, const int depth)
{
if (depth== p*q){
sol.push(Node(x, y));
return 1;
}
ins[x][y]= 1;
for (int i= 0; i< 8; ++i){
int nx= x+ step[i][0], ny= y+step[i][1];
if (nx> 0 && nx<= q && ny> 0 && ny<= p && !ins[nx][ny]){
if (DFS(nx, ny, depth+1)){
sol.push(Node(x, y));
return 1;
}
}
}
ins[x][y]= 0;
return 0;
}
int main(int argc, char const *argv[])
{
int kase;
scanf("%d", &kase);
for (int sn= 1; sn<= kase; ++sn){
stack<Node> empty;
swap(sol, empty);
scanf("%d %d", &p, &q);
int ok= 0;
for (int i= 1; i<= q; ++i){
for (int j= 1; j<= p; ++j){
memset(ins, 0, sizeof(ins));
ok= DFS(i, j, 1);
if (ok){
goto OK;
}
}
}
OK: PrintAns(ok, sn);
}
return 0;
}