这道棋盘题还是挺经典的,问题在于被一个新奇点子卡住好久。
本质上,这道题是一个棋盘中的哈密顿链路问题,这道题一个很经典的优化思路(很多人尝试,都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; }