A* 算法求解八数码问题,POJ 1077 Eight
1
/**/
/*
2
3A* 算法求解八数码问题
4
5
6----问题描述:
7
8经典八数码问题,
9在3×3的方格棋盘上,分别摆放着1到8这八个数码,剩余一个方格为空白。
10
11如下为一个状态,
12
131 2 3
14
15x 4 6
16
177 5 8
18
19其中 x 代表空白方格。
20
21
22现给定初始状态,要求对空白方格执行
23
24左移(l,空白方格与其左边方格互换),
25右移(r,空白方格与其右边方格互换),
26上移(u,空白方格与其上边方格互换),
27下移(d,空白方格与其下边方格互换),
28
29这四个操作使得棋盘变换为如下的
30
311 2 3
32
334 5 6
34
357 8 x
36
37的目标状态。
38
39
40----输入:
41
42初始状态。
43
44形如
45
461 2 3 x 4 6 7 5 8
47
48表示
49
501 2 3
51
52x 4 6
53
547 5 8
55
56
57----输出:
58
59如果无解,输出字符串"unsolvable";
60如果有解,输出变换过程,为包含字符 'l','r','u','d' 的字符串,各字符的含义见上文。
61
62
63----样例输入:
64
652 3 4 1 5 x 7 6 8
66
67
68----样例输出:
69
70ullddrurdllurdruldr
71
72
73----分析:
74
75本问题实为 POJ 1077 Eight,前年写的代码,今天加上注释,作为对 A* 的复习。
76
77这里只要求找出一个解即可,不必找出最优解,且空间不大,仅 9!,因而 A* 具有优势。
78
79简单解释几个地方,具体见代码注释。
80
811.排列转化为序数
82 例,1 2 3 这三个数字的全排列,按字典序,依次为
83
84 123 -- 0
85 132 -- 1
86 213 -- 2
87 231 -- 3
88 312 -- 4
89 321 -- 5
90
91 其中,左侧为排列,右侧为其序数。
92 转化算法此处不再赘述。
93
942.对形如
95
96 1 2 3
97
98 x 4 6
99
100 7 5 8
101
102 的状态,表示为整数 123946758,其中 x 用数字 9 代替。
103
1043.将一个状态视为数字 1-9 的一个排列,将此排列转化为序数,作为此状态的 HASH 值。
105
1064.使用数据结构 堆 加速挑选最优值。
107
1085.函数 g 的计算,此状态在搜索树中的父结点的数量。
109
1106.函数 h 的计算,见代码 calcH 函数。
111
112
113*/
114
115
116 #include < stdio.h >
117 #include < string .h >
118 #include < stdlib.h >
119
120 #define L 362880
121 #define MAXMAX 2123456789
122
123 typedef struct
124 {
125 int arrange, preIndex, g, h, f, flag; // flag -1 closed, 0 no, 1 open
126 char choice;
127} State;
128
129 State state[ L ];
130 int start, goal, startIndex, goalIndex;
131
132 // 排列转化为序数
133 int arrangeToIndex( int arrange ) {
134 int i, j, k, index = 0, t = 0, d[ 10 ];
135 while ( arrange ) {
136 d[ ++t ] = arrange % 10;
137 arrange /= 10;
138 }
139 for ( i = t; i > 1; --i ) {
140 k = 0;
141 for ( j = 1; j < i; ++j ) {
142 if ( d[ i ] > d[ j ] ) ++k;
143 }
144 index = index * i + k;
145 }
146 return index;
147}
148
149 // 堆
150 int heap[ L + 4 ], heapIndex[ L + 4 ], heapN;
151
152 void heapUp( int j ) {
153 int i = j / 2, x = heap[ j ];
154 while ( i > 0 ) {
155 if ( state[ heap[ i ] ].f <= state[ x ].f ) break;
156 heapIndex[ heap[ j ] = heap[ i ] ] = j;
157 j = i;
158 i = j / 2;
159 }
160 heapIndex[ heap[ j ] = x ] = j;
161}
162
163 void heapDown( int i ) {
164 int j = i + i, x = heap[ i ];
165 while ( j <= heapN ) {
166 if ( ( j < heapN ) && ( state[ heap[ j ] ].f > state[ heap[ j + 1 ] ].f ) ) ++j;
167 if ( state[ x ].f <= state[ heap[ j ] ].f ) break;
168 heapIndex[ heap[ i ] = heap[ j ] ] = i;
169 i = j;
170 j = i + i;
171 }
172 heapIndex[ heap[ i ] = x ] = i;
173}
174
175 int heapPop() {
176 int x = heap[ 1 ];
177 heapIndex[ heap[ 1 ] = heap[ heapN-- ] ] = 1;
178 if ( heapN > 1 ) {
179 heapDown( 1 );
180 }
181 return x;
182}
183
184 void heapAdd( int x ) {
185 ++heapN;
186 heapIndex[ heap[ heapN ] = x ] = heapN;
187 heapUp( heapN );
188}
189
190 // 计算状态的 h 函数
191 int calcH( int arrange ) {
192 int p, i, h = 0;
193 for ( i = 8; i >= 0; --i ) {
194 p = arrange % 10 - 1;
195 arrange /= 10;
196 h += abs( p % 3 - i % 3 ) + abs( p / 3 - i / 3 );
197 }
198 return h;
199}
200
201 int input() {
202 int ch, i;
203 start = goal = 0;
204 for ( i = 0; i < 9; ++i ) {
205 do {
206 ch = getchar();
207 } while ( ( ch != EOF ) && ( ( ch < '1' ) || ( ch > '8' ) ) && ( ch != 'x' ) );
208 if ( ch == EOF ) return 0;
209 if ( ch == 'x' ) start = start * 10 + 9;
210 else start = start * 10 + ch - '0';
211 goal = goal * 10 + i + 1;
212 }
213 return 1;
214}
215
216 // 判断是否无解
217 int noAns() {
218 int a = start, d[ 10 ], t = 0, sum = 0, i, j;
219 while ( a ) {
220 d[ t++ ] = a % 10;
221 a /= 10;
222 }
223 for ( i = 1; i < t; ++i )
224 for ( j = 0; j < i; ++j )
225 if ( ( d[ i ] > d[ j ] ) && ( d[ i ] != 9 ) ) ++sum;
226 return sum % 2;
227}
228
229 char choice[ 4 ];
230 int nextIndex[ 4 ];
231 void next( int arrange ) {
232 static int DI[] = { 0, 1, 0, -1 };
233 static int DJ[] = { 1, 0, -1, 0 };
234 static char DC[] = { 'l', 'u', 'r', 'd' };
235 static int p[ 3 ][ 3 ];
236 int i, j, i0, j0, x, y, k;
237 for ( i = 0; i < 3; ++i )
238 for ( j = 0; j < 3; ++j ) {
239 p[ i ][ j ] = arrange % 10;
240 arrange /= 10;
241 if ( p[ i ][ j ] == 9 ) {
242 i0 = i;
243 j0 = j;
244 }
245 }
246 for ( k = 0; k < 4; ++k ) {
247 i = i0 + DI[ k ];
248 j = j0 + DJ[ k ];
249 if ( ( i >= 0 ) && ( i < 3 ) && ( j >= 0 ) && ( j < 3 ) ) {
250 p[ i0 ][ j0 ] = p[ i ][ j ];
251 p[ i ][ j ] = 9;
252 arrange = 0;
253 for ( x = 2; x >= 0; --x )
254 for ( y = 2; y >= 0; --y )
255 arrange = arrange * 10 + p[ x ][ y ];
256 p[ i ][ j ] = p[ i0 ][ j0 ];
257 x = nextIndex[ k ] = arrangeToIndex( arrange );
258 choice[ k ] = DC[ k ];
259 if ( state[ x ].arrange == 0 ) {
260 state[ x ].arrange = arrange;
261 state[ x ].h = calcH( arrange );
262 }
263 }
264 else {
265 nextIndex[ k ] = -1;
266 }
267 }
268}
269
270 int astar() {
271 int i, j, k, ng, nf;
272 if ( noAns() ) return 0;
273 startIndex = arrangeToIndex( start );
274 goalIndex = arrangeToIndex( goal );
275 if ( start == goal ) return 1;
276
277 memset( state, 0, sizeof(state) );
278 state[ startIndex ].arrange = start;
279 state[ startIndex ].flag = 1;
280 state[ startIndex ].g = 0;
281 state[ startIndex ].h = state[ startIndex ].f = calcH( start );
282 heapN = 0;
283 heapAdd( startIndex );
284 while ( heapN > 0 ) {
285 i = heapPop();
286 if ( i == goalIndex ) return 1;
287 state[ i ].flag = -1;
288 ng = state[ i ].g + 1;
289 next( state[ i ].arrange );
290 for ( k = 0; k < 4; ++k ) {
291 j = nextIndex[ k ];
292 if ( j < 0 ) continue;
293 nf = ng + state[ j ].h;
294 if ( ( state[ j ].flag == 0 ) || ( ( state[ j ].flag == 1 ) && ( nf < state[ j ].f ) ) ) {
295 state[ j ].preIndex = i;
296 state[ j ].choice = choice[ k ];
297 state[ j ].g = ng;
298 state[ j ].f = nf;
299 if ( state[ j ].flag > 0 ) {
300 heapUp( heapIndex[ j ] );
301 heapDown( heapIndex[ j ] );
302 }
303 else {
304 heapAdd( j );
305 state[ j ].flag = 1;
306 }
307 }
308 }
309 }
310 return 0;
311}
312
313 void output() {
314 int i, top = -1;
315 char stack[ 1000 ];
316 for ( i = goalIndex; i != startIndex; i = state[ i ].preIndex ) {
317 stack[ ++top ] = state[ i ].choice;
318 }
319 for ( i = top; i >= 0; --i ) {
320 printf( "%c", stack[ i ] );
321 }
322 printf( "\n" );
323}
324
325 int main() {
326 while ( input() ) {
327 if ( astar() ) output();
328 else printf( "unsolvable\n" );
329 }
330 return 0;
331}
332
2
3A* 算法求解八数码问题
4
5
6----问题描述:
7
8经典八数码问题,
9在3×3的方格棋盘上,分别摆放着1到8这八个数码,剩余一个方格为空白。
10
11如下为一个状态,
12
131 2 3
14
15x 4 6
16
177 5 8
18
19其中 x 代表空白方格。
20
21
22现给定初始状态,要求对空白方格执行
23
24左移(l,空白方格与其左边方格互换),
25右移(r,空白方格与其右边方格互换),
26上移(u,空白方格与其上边方格互换),
27下移(d,空白方格与其下边方格互换),
28
29这四个操作使得棋盘变换为如下的
30
311 2 3
32
334 5 6
34
357 8 x
36
37的目标状态。
38
39
40----输入:
41
42初始状态。
43
44形如
45
461 2 3 x 4 6 7 5 8
47
48表示
49
501 2 3
51
52x 4 6
53
547 5 8
55
56
57----输出:
58
59如果无解,输出字符串"unsolvable";
60如果有解,输出变换过程,为包含字符 'l','r','u','d' 的字符串,各字符的含义见上文。
61
62
63----样例输入:
64
652 3 4 1 5 x 7 6 8
66
67
68----样例输出:
69
70ullddrurdllurdruldr
71
72
73----分析:
74
75本问题实为 POJ 1077 Eight,前年写的代码,今天加上注释,作为对 A* 的复习。
76
77这里只要求找出一个解即可,不必找出最优解,且空间不大,仅 9!,因而 A* 具有优势。
78
79简单解释几个地方,具体见代码注释。
80
811.排列转化为序数
82 例,1 2 3 这三个数字的全排列,按字典序,依次为
83
84 123 -- 0
85 132 -- 1
86 213 -- 2
87 231 -- 3
88 312 -- 4
89 321 -- 5
90
91 其中,左侧为排列,右侧为其序数。
92 转化算法此处不再赘述。
93
942.对形如
95
96 1 2 3
97
98 x 4 6
99
100 7 5 8
101
102 的状态,表示为整数 123946758,其中 x 用数字 9 代替。
103
1043.将一个状态视为数字 1-9 的一个排列,将此排列转化为序数,作为此状态的 HASH 值。
105
1064.使用数据结构 堆 加速挑选最优值。
107
1085.函数 g 的计算,此状态在搜索树中的父结点的数量。
109
1106.函数 h 的计算,见代码 calcH 函数。
111
112
113*/
114
115
116 #include < stdio.h >
117 #include < string .h >
118 #include < stdlib.h >
119
120 #define L 362880
121 #define MAXMAX 2123456789
122
123 typedef struct
124 {
125 int arrange, preIndex, g, h, f, flag; // flag -1 closed, 0 no, 1 open
126 char choice;
127} State;
128
129 State state[ L ];
130 int start, goal, startIndex, goalIndex;
131
132 // 排列转化为序数
133 int arrangeToIndex( int arrange ) {
134 int i, j, k, index = 0, t = 0, d[ 10 ];
135 while ( arrange ) {
136 d[ ++t ] = arrange % 10;
137 arrange /= 10;
138 }
139 for ( i = t; i > 1; --i ) {
140 k = 0;
141 for ( j = 1; j < i; ++j ) {
142 if ( d[ i ] > d[ j ] ) ++k;
143 }
144 index = index * i + k;
145 }
146 return index;
147}
148
149 // 堆
150 int heap[ L + 4 ], heapIndex[ L + 4 ], heapN;
151
152 void heapUp( int j ) {
153 int i = j / 2, x = heap[ j ];
154 while ( i > 0 ) {
155 if ( state[ heap[ i ] ].f <= state[ x ].f ) break;
156 heapIndex[ heap[ j ] = heap[ i ] ] = j;
157 j = i;
158 i = j / 2;
159 }
160 heapIndex[ heap[ j ] = x ] = j;
161}
162
163 void heapDown( int i ) {
164 int j = i + i, x = heap[ i ];
165 while ( j <= heapN ) {
166 if ( ( j < heapN ) && ( state[ heap[ j ] ].f > state[ heap[ j + 1 ] ].f ) ) ++j;
167 if ( state[ x ].f <= state[ heap[ j ] ].f ) break;
168 heapIndex[ heap[ i ] = heap[ j ] ] = i;
169 i = j;
170 j = i + i;
171 }
172 heapIndex[ heap[ i ] = x ] = i;
173}
174
175 int heapPop() {
176 int x = heap[ 1 ];
177 heapIndex[ heap[ 1 ] = heap[ heapN-- ] ] = 1;
178 if ( heapN > 1 ) {
179 heapDown( 1 );
180 }
181 return x;
182}
183
184 void heapAdd( int x ) {
185 ++heapN;
186 heapIndex[ heap[ heapN ] = x ] = heapN;
187 heapUp( heapN );
188}
189
190 // 计算状态的 h 函数
191 int calcH( int arrange ) {
192 int p, i, h = 0;
193 for ( i = 8; i >= 0; --i ) {
194 p = arrange % 10 - 1;
195 arrange /= 10;
196 h += abs( p % 3 - i % 3 ) + abs( p / 3 - i / 3 );
197 }
198 return h;
199}
200
201 int input() {
202 int ch, i;
203 start = goal = 0;
204 for ( i = 0; i < 9; ++i ) {
205 do {
206 ch = getchar();
207 } while ( ( ch != EOF ) && ( ( ch < '1' ) || ( ch > '8' ) ) && ( ch != 'x' ) );
208 if ( ch == EOF ) return 0;
209 if ( ch == 'x' ) start = start * 10 + 9;
210 else start = start * 10 + ch - '0';
211 goal = goal * 10 + i + 1;
212 }
213 return 1;
214}
215
216 // 判断是否无解
217 int noAns() {
218 int a = start, d[ 10 ], t = 0, sum = 0, i, j;
219 while ( a ) {
220 d[ t++ ] = a % 10;
221 a /= 10;
222 }
223 for ( i = 1; i < t; ++i )
224 for ( j = 0; j < i; ++j )
225 if ( ( d[ i ] > d[ j ] ) && ( d[ i ] != 9 ) ) ++sum;
226 return sum % 2;
227}
228
229 char choice[ 4 ];
230 int nextIndex[ 4 ];
231 void next( int arrange ) {
232 static int DI[] = { 0, 1, 0, -1 };
233 static int DJ[] = { 1, 0, -1, 0 };
234 static char DC[] = { 'l', 'u', 'r', 'd' };
235 static int p[ 3 ][ 3 ];
236 int i, j, i0, j0, x, y, k;
237 for ( i = 0; i < 3; ++i )
238 for ( j = 0; j < 3; ++j ) {
239 p[ i ][ j ] = arrange % 10;
240 arrange /= 10;
241 if ( p[ i ][ j ] == 9 ) {
242 i0 = i;
243 j0 = j;
244 }
245 }
246 for ( k = 0; k < 4; ++k ) {
247 i = i0 + DI[ k ];
248 j = j0 + DJ[ k ];
249 if ( ( i >= 0 ) && ( i < 3 ) && ( j >= 0 ) && ( j < 3 ) ) {
250 p[ i0 ][ j0 ] = p[ i ][ j ];
251 p[ i ][ j ] = 9;
252 arrange = 0;
253 for ( x = 2; x >= 0; --x )
254 for ( y = 2; y >= 0; --y )
255 arrange = arrange * 10 + p[ x ][ y ];
256 p[ i ][ j ] = p[ i0 ][ j0 ];
257 x = nextIndex[ k ] = arrangeToIndex( arrange );
258 choice[ k ] = DC[ k ];
259 if ( state[ x ].arrange == 0 ) {
260 state[ x ].arrange = arrange;
261 state[ x ].h = calcH( arrange );
262 }
263 }
264 else {
265 nextIndex[ k ] = -1;
266 }
267 }
268}
269
270 int astar() {
271 int i, j, k, ng, nf;
272 if ( noAns() ) return 0;
273 startIndex = arrangeToIndex( start );
274 goalIndex = arrangeToIndex( goal );
275 if ( start == goal ) return 1;
276
277 memset( state, 0, sizeof(state) );
278 state[ startIndex ].arrange = start;
279 state[ startIndex ].flag = 1;
280 state[ startIndex ].g = 0;
281 state[ startIndex ].h = state[ startIndex ].f = calcH( start );
282 heapN = 0;
283 heapAdd( startIndex );
284 while ( heapN > 0 ) {
285 i = heapPop();
286 if ( i == goalIndex ) return 1;
287 state[ i ].flag = -1;
288 ng = state[ i ].g + 1;
289 next( state[ i ].arrange );
290 for ( k = 0; k < 4; ++k ) {
291 j = nextIndex[ k ];
292 if ( j < 0 ) continue;
293 nf = ng + state[ j ].h;
294 if ( ( state[ j ].flag == 0 ) || ( ( state[ j ].flag == 1 ) && ( nf < state[ j ].f ) ) ) {
295 state[ j ].preIndex = i;
296 state[ j ].choice = choice[ k ];
297 state[ j ].g = ng;
298 state[ j ].f = nf;
299 if ( state[ j ].flag > 0 ) {
300 heapUp( heapIndex[ j ] );
301 heapDown( heapIndex[ j ] );
302 }
303 else {
304 heapAdd( j );
305 state[ j ].flag = 1;
306 }
307 }
308 }
309 }
310 return 0;
311}
312
313 void output() {
314 int i, top = -1;
315 char stack[ 1000 ];
316 for ( i = goalIndex; i != startIndex; i = state[ i ].preIndex ) {
317 stack[ ++top ] = state[ i ].choice;
318 }
319 for ( i = top; i >= 0; --i ) {
320 printf( "%c", stack[ i ] );
321 }
322 printf( "\n" );
323}
324
325 int main() {
326 while ( input() ) {
327 if ( astar() ) output();
328 else printf( "unsolvable\n" );
329 }
330 return 0;
331}
332