poj1077
题意:给出一个八数码问题,求解法,不可解则输出unsolvable。
分析:可以用ida*算法,估价函数可以使用每个数码到其最终位置的最短距离之和。对于不可解的判断,我这里用迭代深度大于100时判定为不可解。
还有一种更高级的无解判断方法。就是将八数码矩阵中的空格忽略,然后将8个数字排成一排,第二行接在第一行后面,第三行接在第二行后面,通过观察我们发现移动空格不会影响这个8个数字组成的数列中逆序数队的奇偶性,因此如果逆序数对的奇偶性与目标状态不同则一定无解。至于为什么奇偶性相同就一定有解,我就不知道为什么了,不过这个命题确实是正确的。
可以将这种方法做适当修改并推广至15数码问题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <stack> #include <cmath> using namespace std; const int maxn = 10; char ans[100]; int tot, dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}}; struct Node { char map[maxn]; int g, move, xpos; }starts; void init() { for (int i = 0; i < 9; i++) { starts.map[i] = ' '; while (starts.map[i] == ' ') scanf("%c",&starts.map[i]); if (starts.map[i] == 'x') { starts.map[i] = 9; starts.xpos = i; } else starts.map[i] -= '0'; } } int h(Node &a) { int x1, x2, y1, y2, i, r = 0; for (i = 0; i < 9; i++) { x1 = i / 3; y1 = i % 3; x2 = (a.map[i] - 1) / 3; y2 = (a.map[i] - 1) % 3; r += abs(x1 - x2) + abs(y1 - y2); } return r; } Node getchild(int a, Node ¤ts) { int x, y, pos, i; Node r; x = currents.xpos / 3 + dir[a][0]; y = currents.xpos % 3 + dir[a][1]; r.xpos = -1; if (x < 0 || y < 0 || x > 2 || y > 2) return r; pos = x * 3 + y; r.xpos = pos; r.g = currents.g + 1; r.move = a; for (i = 0; i < 9; i++) r.map[i] = currents.map[i]; r.map[pos] = 9; r.map[currents.xpos] = currents.map[pos]; return r; } bool ida() { int pathlimit, i, temp, next; bool success = 0; Node currents, child; next = h(starts)/2; stack<Node> stk; do { pathlimit = next; if (pathlimit > 100) return false; tot = 0; starts.g = 0; starts.move = -1; next = 200; stk.push(starts); do { currents = stk.top(); ans[currents.g] = currents.move; stk.pop(); temp = h(currents); if (temp == 0) { tot = currents.g; success = true; } else if (pathlimit >= currents.g + temp / 2) { for (i = 0; i < 4; i++) { child = getchild(i, currents); if (child.xpos != -1 && abs(child.move - currents.move) != 2) stk.push(child); } }else if (next > currents.g + temp / 2) next = currents.g + temp / 2; }while (!success && !stk.empty()); }while (!success); return true; } void print() { int i; for (i = 1; i <= tot; i++) switch(ans[i]) { case 0: printf("u"); break; case 1: printf("r"); break; case 2: printf("d"); break; case 3: printf("l"); break; } printf("\n"); } int main() { //freopen("t.txt", "r", stdin); init(); if (ida()) print(); else printf("unsolvable\n"); return 0; }