10085 - The most distant state
题目大意:就和八码数问题类似,只是题目没有给最终的状态,要求你自己写出最终的状态,并且给出最短的路径。
解题思路:和八码数的解题思路是相同的,只是不给最终的状态,而是让它自己去bfs()直到最后已经不能在走的地步(再走下去就会重复的情况),这里的判重用了哈希判重。
然后就是存储路径问题:开了一个数组dis【】用来存放走到这个状态是哪个方向来的。然后在开一个fa【】数组:表示i的祖先是fa【i】。最终的状态是保存在st[rear - 1],那么它的前一个就是fa【rear- 1】,这样就可以反向的找出这条路径,存放到out数组中,最后就可以输出路径。
#include<stdio.h> #include<string.h> const int N = 3; const int M = 1000000; int n, head[M], next[M], dis[M], fa[M]; struct state{ int s[N][N]; }st[M]; const char dx[] = {-1, 0, 1, 0}; const char dy[] = {0, -1, 0, 1}; const char f[] = "ULDR"; int hash(state &s1){ int v = 0; for(int i = 0; i < N; i++) for(int j = 0; j < N; j++){ v = v * 10 + s1.s[i][j]; } return v % M; } int try_to_insert(int s){ int h = hash(st[s]); int u = head[h]; while(u){ if(memcmp(st[u].s, st[s].s, sizeof(st[s]).s) == 0) return 0; u = next[u]; } next[s] = head[h]; head[h] = s; return 1; } int bfs(){ memset(head, 0, sizeof(head)); memset(fa, 0, sizeof(fa)); int front = 1, rear = 2; while(front < rear){ state &s1 = st[front]; int x, y, i, j; for(i = 0; i < N; i++) for(j = 0; j < N; j++) if(s1.s[i][j] == 0){ x = i; y = j; break; } for(i = 0; i < 4; i++){ int nx = x + dx[i]; int ny = y + dy[i]; if(nx >= 0 && nx < N && ny >= 0 && ny < N){ state &t = st[rear]; memcpy(&t.s, &s1.s, sizeof(s1.s)); int tmp; tmp = t.s[nx][ny]; t.s[nx][ny] = t.s[x][y]; t.s[x][y] = tmp; dis[rear] = i; fa[rear] = front; if(try_to_insert(rear)) rear++; } } front++; } return rear; } int main() { scanf("%d", &n); for(int v = 0; v < n; v++){ int i, j; for(i = 0; i < N; i++) for(j = 0; j < N; j++) scanf("%d", &st[1].s[i][j]); printf("Puzzle #%d\n", v + 1); int rear = bfs(); for(i = 0; i < N; i++) for(j = 0; j < N; j++){ if(j != N - 1) printf("%d ", st[rear - 1].s[i][j]); else printf("%d\n", st[rear - 1].s[i][j]); } int k = rear - 1, out[10000]; for(i = 0; ; i++){ if(fa[k]){ out[i] = dis[k]; k = fa[k]; } else break; } for(j = i - 1; j >= 0; j--) printf("%c", f[out[j]]); printf("\n\n"); } return 0; }