这个看起来是童年回忆:)
大体思路是,将每个排列状态看成图中的一个点,状态之间转换说明有边。然后用bfs,如果遍历完之后还是没有找到目标状态,
则说明是无解的,否则输出步数。具体想法写在代码里吧,多多理解。
#include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> #include <cmath> #include <vector> #include <algorithm> using namespace std; const int N = 1000000, HN = 1000003; // linked list for hash table. int head[HN], next[N]; int state[N][9], goal[9]; // # steps int dist[N]; const int dx[4] = {-1, 1, 0, 0}; const int dy[4] = {0, 0, -1, 1}; // map into a number of 9 digits int hash(int *arr) { int v = 0; for (int i = 0; i < 9; i++) { v = v * 10 + arr[i]; } // make sure not overflow return v % HN; } // insert a state bool tryInsert(int rear) { int h = hash(state[rear]); int u = head[h]; while (u) { // if repeated if (!memcmp(state[u], state[rear], sizeof(state[0]))) return false; u = next[u]; } // insert rear to the front next[rear] = head[h]; head[h] = rear; return true; } int bfs() { // initiate head memset(head, 0, sizeof(head)); //memset(dist, 0, sizeof(dist)); int front = 1; int rear = 2; while (front < rear) { // same, memcmp return 0 // means find goal if (!memcmp(goal, state[front], sizeof(state[0]))) return front; int z; // find 0 for (z = 0 ; z < 9; z++) if (!state[front][z]) break; int x = z / 3; int y = z % 3; for (int d = 0; d < 4; d++) { int nx = x + dx[d]; int ny = y + dy[d]; int nz = 3 * nx + ny; // judge if still in if (nx >= 0 && nx < 3 && ny >= 0 && ny < 3) { memcpy(&state[rear], &state[front], sizeof(state[0])); // move state[rear][nz] = state[front][z]; state[rear][z] = state[front][nz]; dist[rear] = dist[front] + 1; if (tryInsert(rear)) rear ++; } } // front pop front ++; } return 0; } int main() { //freopen("hhInput.in", "r", stdin); for (int i = 0; i < 9; i++) // 1 3 0 8 2 4 7 6 5 cin >> state[1][i]; for (int i = 0; i < 9; i++) // 1 2 3 8 0 4 7 6 5 cin >> goal[i]; int ans = bfs(); if (ans > 0) cout << dist[ans] << endl; else cout << "-1" << endl; return 0; }
时间: 2024-10-30 16:43:22