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

posted on 2012-06-05 15:06 coreBugZJ 閱讀(2654) 評論(4) 編輯 收藏 引用 所屬分類: ACM 、Algorithm 、課內作業 、Intelligence