八数码问题的变形,bfs+哈希,打印路径时花了点时间,用哈希表next数组的原理进行回退就可以将问题解决。
代码如下:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> using namespace std; const int MAXSIZE = 1000003; const int dx[4] = {-1, 1, 0, 0}; const int dy[4] = {0, 0, -1, 1}; int back[MAXSIZE], path[MAXSIZE][9], dist[MAXSIZE]; int head[MAXSIZE], next[MAXSIZE]; char ac[MAXSIZE], save[100]; int Hash(int s) { int v = 0; for(int i=0; i<9; i++) v = v * 10 + path[s][i]; return v % MAXSIZE; } int insert(int s) { int h = Hash(s); int u = head[h]; while(u) { if(!memcmp(path[u], path[s], sizeof(path[s]))) return 0; u = next[u]; } next[s] = head[h]; head[h] = s; return 1; } int bfs() { memset(head, 0, sizeof(head)); int front = 1, rear = 2; while(front < rear) { int z; for(z=0; z<9; z++) if(!path[front][z]) break; int x = z/3, y = z%3; for(int i=0; i<4; i++) { int newx = x + dx[i], newy = y +dy[i]; int newz = newx * 3 +newy; if(newx >= 0 && newx < 3 && newy >= 0 && newy < 3) { memcpy(path[rear], path[front], sizeof(path[front])); path[rear][newz] = path[front][z]; path[rear][z] = path[front][newz]; dist[rear] = dist[front] + 1; if(insert(rear)) { back[rear] = front; switch(i) { case 0: ac[rear] = 'U'; break; case 1: ac[rear] = 'D'; break; case 2: ac[rear] = 'L'; break; case 3: ac[rear] = 'R'; break; } rear++; } } } ++front; } return rear - 1; } int main() { #ifdef test freopen("sample.txt", "r", stdin); #endif int num, goal; scanf("%d", &num); for(int i=1; i<=num; i++) { int sum = 0; back[1] = 0; for(int j=0; j<9; j++) scanf("%d", &path[1][j]); goal = bfs(); printf("Puzzle #%d\n", i); for(int j=0; j<3; j++) { printf("%d", path[goal][j*3]); for(int k=1; k<3; k++) printf(" %d", path[goal][j*3+k]); puts(""); } while(goal) { save[++sum] = ac[goal]; goal = back[goal]; } for (int i=sum-1; i; i--) printf("%c", save[i]); printf("\n\n"); } return 0; }