A* 算法求解八数码问题,POJ 1077 Eight
1
/**/
/*
2![]()
3
A* 算法求解八数码问题
4![]()
5![]()
6
----问题描述:
7![]()
8
经典八数码问题,
9
在3×3的方格棋盘上,分别摆放着1到8这八个数码,剩余一个方格为空白。
10![]()
11
如下为一个状态,
12![]()
13
1 2 3
14![]()
15
x 4 6
16![]()
17
7 5 8
18![]()
19
其中 x 代表空白方格。
20![]()
21![]()
22
现给定初始状态,要求对空白方格执行
23![]()
24
左移(l,空白方格与其左边方格互换),
25
右移(r,空白方格与其右边方格互换),
26
上移(u,空白方格与其上边方格互换),
27
下移(d,空白方格与其下边方格互换),
28![]()
29
这四个操作使得棋盘变换为如下的
30![]()
31
1 2 3
32![]()
33
4 5 6
34![]()
35
7 8 x
36![]()
37
的目标状态。
38![]()
39![]()
40
----输入:
41![]()
42
初始状态。
43![]()
44
形如
45![]()
46
1 2 3 x 4 6 7 5 8
47![]()
48
表示
49![]()
50
1 2 3
51![]()
52
x 4 6
53![]()
54
7 5 8
55![]()
56![]()
57
----输出:
58![]()
59
如果无解,输出字符串"unsolvable";
60
如果有解,输出变换过程,为包含字符 'l','r','u','d' 的字符串,各字符的含义见上文。
61![]()
62![]()
63
----样例输入:
64![]()
65
2 3 4 1 5 x 7 6 8
66![]()
67![]()
68
----样例输出:
69![]()
70
ullddrurdllurdruldr
71![]()
72![]()
73
----分析:
74![]()
75
本问题实为 POJ 1077 Eight,前年写的代码,今天加上注释,作为对 A* 的复习。
76![]()
77
这里只要求找出一个解即可,不必找出最优解,且空间不大,仅 9!,因而 A* 具有优势。
78![]()
79
简单解释几个地方,具体见代码注释。
80![]()
81
1.排列转化为序数
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![]()
94
2.对形如
95![]()
96
1 2 3
97![]()
98
x 4 6
99![]()
100
7 5 8
101![]()
102
的状态,表示为整数 123946758,其中 x 用数字 9 代替。
103![]()
104
3.将一个状态视为数字 1-9 的一个排列,将此排列转化为序数,作为此状态的 HASH 值。
105![]()
106
4.使用数据结构 堆 加速挑选最优值。
107![]()
108
5.函数 g 的计算,此状态在搜索树中的父结点的数量。
109![]()
110
6.函数 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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132
133

134
135

136
137
138
139

140
141

142
143
144
145
146
147
148
149
150
151
152

153
154

155
156
157
158
159
160
161
162
163

164
165

166
167
168
169
170
171
172
173
174
175

176
177
178

179
180
181
182
183
184

185
186
187
188
189
190
191

192
193

194
195
196
197
198
199
200
201

202
203
204

205

206
207
208
209
210
211
212
213
214
215
216
217

218
219

220
221
222
223
224
225
226
227
228
229
230
231

232

233

234

235
236
237
238

239
240
241

242
243
244
245
246

247
248
249

250
251
252
253
254
255
256
257
258
259

260
261
262
263
264

265
266
267
268
269
270

271
272
273
274
275
276
277
278
279
280
281
282
283
284

285
286
287
288
289
290

291
292
293
294

295
296
297
298
299

300
301
302
303

304
305
306
307
308
309
310
311
312
313

314
315
316

317
318
319

320
321
322
323
324
325

326

327
328
329
330
331
332