1 /*复杂题目模板加注解*/
2 # include <stdio.h>
3 # include <mem.h>
4
5 # define MAXN (362880 + 5)
6
7 typedef struct
8 {
9 char a[9];
10 }state;
11
12 const int dir[4][2] = {{-1,0}, {0,1}, {1,0}, {0,-1}};
13 int fact[9];
14
15 int front, rear;
16 state cur, nst; /* new state */
17 char vis[MAXN];
18 char dist[MAXN]; /* 求的是最短距离( < 100),可以用 char 类型 */
19 state Q[MAXN/2];
20
21
22 void read(state *s);
23 int inversions(state s);
24 int cantor(state s);
25 void init_fact(void);
26 int bfs_d(state start, state goal);
27
28 int main()
29 {
30 state start, goal;
31
32 freopen("in.txt", "r", stdin);
33 freopen("out.txt", "w", stdout);
34
35 init_fact();
36
37 read(&start);/*指针引用*/
38 read(&goal);
39
40 if (inversions(start)%2 == inversions(goal)%2)/
41 {/*判断能不能到达最终状态,如果能达到最终状态的话,那么格子中的个数在后面有几个比他小的数的和的奇偶是不变的,无论怎么变换,可以用归纳推理证明*/
42 printf("%d\n", bfs_d(start, goal));
43 }
44 else puts("-1");/*找不到最终的状态*/
45
46 return 0;
47 }
48
49 int bfs_d(state start, state goal)
50 {
51 int i, x, y, nx, ny, ct, nt;
52
53 memset(vis, 0, sizeof(vis));
54 memset(dist, 0, sizeof(dist));
55
56 front = 1;
57 Q[front] = start;
58 rear = 2;
59 Q[rear++] = goal;
60 vis[cantor(start)] = 1; /* 1 表示从起始节点扩展得到 */
61 vis[cantor(goal)] = 2; /* 2 表示从目标节点扩展得到 */
62
63 while (front < rear)
64 {
65 cur = Q[front++];
66 ct = cantor(cur);
67 for (i = 0; cur.a[i] && i < 9; ++i);/*找出0的位置*/
68 x = i / 3;/*求出0所在的行数列数*/
69 y = i % 3;
70 for (i = 0; i < 4; ++i)
71 {
72 nx = x + dir[i][0];/*把0向四周扩展*/
73 ny = y + dir[i][1];
74 if (nx>=0 && nx<3 && ny>=0 && ny<3)
75 {
76 nst = cur;
77 nst.a[x*3+y] = cur.a[nx*3+ny];/*互换0的位置与对应元素的位置*/
78 nst.a[nx*3+ny] = 0;
79 if (!vis[nt = cantor(nst)])/*判断当前这个状态是否已经到过*/
80 {
81 Q[rear++] = nst;
82 /* foot[nt] = ct; */
83 dist[nt] = dist[ct] + 1;
84 vis[nt] = vis[ct];/*转移扩展的方向*/
85 }
86 else if (vis[ct] != vis[nt])/*如果已经到过,就是两者变换的次数和加上最后一次变化*/
87 {/*这是双向广搜的精髓,判断两个点是从不同的方向转移来的*/
88 return 1 + dist[nt] + dist[ct];
89 }
90 }
91 }
92 }
93
94 return -1;
95 }
96
97 void read(state *s)
98 {
99 int i;
100 char c[5];
101
102 for (i = 0; i < 9; ++i)
103 {
104 scanf("%s", c);
105 if (c[0] == ‘x‘) (*s).a[i] = 0;
106 else (*s).a[i] = c[0] - ‘0‘;
107 }
108 }
109
110 int inversions(state s)
111 {
112 char ch;
113 int i, j, ret;
114
115 ret = 0;
116 for (i = 0; i < 9; ++i)
117 {
118 if (s.a[i] == 0) continue;
119 ch = s.a[i];
120 for (j = i+1; j < 9; ++j)
121 {
122 if (s.a[j] < ch && s.a[j] != 0)
123 ++ret;
124 }
125 }
126
127 return ret;
128 }
129
130 int cantor(state s)/*康托展开应用于哈希表,处理排列问题是不会有冲突的,网上有证明,可以自己看*/
131 {
132 char ch;
133 int i, j, ret, cnt;
134
135 ret = 0;
136 for (i = 0; i < 9; ++i)
137 {
138 cnt = 0;
139 ch = s.a[i];
140 for (j = i+1; j < 9; ++j)
141 {
142 if (s.a[j] < ch)
143 ++cnt;
144 }
145 ret += cnt*fact[8-i];
146 }
147
148 return ret;
149 }
150
151 void init_fact(void)
152 {
153 int i;
154
155 fact[0] = 1;
156 for (i = 1; i < 9; ++i)
157 {
158 fact[i] = i * fact[i-1];/*处理阶乘,整张图一共有9!种状态*/
159 }
160 }