八数码问题

题目

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局,找到一种移动方法,实现从初始布局到目标布局的转变。

思路

依据题意可以优先考虑广度优先算法(BFS),创建一个队列先将根结点(初始状态)入队,然后再依次取出队列中队首元素,判断队首结点数据是否与目标数据相同。如果不同再,将空格可以移动的几个方向移动后的状态保存到结点后依次入队,重复上述出队操作直至找到目标数据或者队空。

深度优先算法

深度优先算法要优先给出遍历的深度,因为数码移动没有限制,除了深度限制没有其他情况可以结束深度遍历,按照一个顺序(如上下左右)进行遍历,待循环到深度限制后开始回溯,回溯到第一个可以新增子节点的结点即可继续顺序往下遍历,此时需要跳过回溯到此节点次数个遍历方向(如第二次回溯到此结点,此结点能向上下左,第二次回溯到此节点要跳过往上和下的方向而去遍历左方向)。

启发式搜索(A*)

启发式搜索(A*) ,在BFS搜索算法中,如果能在搜索的每一步都利用估价函数**f(n)=g(n)+h(n)对表(队列)**中的节点进行排序(g(n)表示从初始结点到任意结点n的实际代价,h(n)表示从结点n到目标点的启发式评估代价),则该搜索算法为A*算法。由于估价函数中带有问题自身的启发性信息,因此,A算法又称为启发式搜索算法。对启发式搜索算法,又可根据搜索过程中选择扩展节点的范围,将其分为全局择优搜索算法和局部择优搜索算法。

在全局择优搜索中,每当需要扩展节点时,总是从表的所有节点中选择一个估价函数值最小的节点进行扩展。其搜索过程可能描述如下:

  1. 把初始节点originalData放入表中,f(originalData)=g(originalData)+h(originalData);
  2. 如果表空则问题无解,如果表非空,取出表(队列)的第一个记录为temp;
  3. 判断temp是否是目标结点,如果是targetData则输出信息,结束运行;如果不是targetData则判断其是否有可拓展结点;
  4. 如果其不可拓展,则返回步骤2;
  5. 如果可拓展,则生成其可拓展的结点,计算每个结点的f(n),并且设置指针指向其父节点后将其存入表中;
  6. 根据表中结点的f(n)值进行从小到大排序后返回步骤2;

eg.

示例


代码及运行结果

广度优先

C++

1
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
/*
* @Author: 转接
* @Date: 2022-03-12 13:10:57
* @LastEditors: 转接
* @LastEditTime: 2022-03-14 12:28:26
* @Description: 八数码问题广度优先求解
*/

#include <iostream>
#include <queue>
#include <time.h>

typedef struct Data{
int data[9]; // 存放数据
int step; // 记录步数
int last; // 上一步操作 上 下 左 右 1 2 3 4
int *action = new int[step];// 每一步操作 上 下 左 右 1 2 3 4
} Data;

int tempPosition[9][2] = { // 位置 上下左右
{0, 5}, // 0号位 0 1 0 1 = 5
{1, 7}, // 1号位 0 1 1 1 = 7
{2, 6}, // 2号位 0 1 1 0 = 6
{3, 13}, // 3号位 1 1 0 1 = 13
{4, 15}, // 4号位 1 1 1 1 = 15
{5, 14}, // 5号位 1 1 1 0 = 14
{6, 9}, // 6号位 1 0 0 1 = 9
{7, 11}, // 7号位 1 0 1 1 = 11
{8, 10}, // 8号位 1 0 1 0 = 10
}; // 上tempPosition[i][1]>=8 下tempPosition[i][1]%8>=4 左tempPosition[i][1]%8%4>=2 右tempPosition[i][1]%8%4%2>=1

int GetNextAction(Data data){
int *temp = data.data;
int i = 0;
for(i = 0; i < 9; i++){
if(temp[i] == 0){
break;
}
}
int tp = tempPosition[i][1];
int last = data.last;
if(last == 1){ // 上一步向上移动
tp = tp - 4; // 不让其向下移动
}else if(last == 2){ // 上一步向下移动
tp = tp - 8; // 不让其向上移动
}else if(last == 3){ // 上一步向左移动
tp = tp - 1; // 不让其向右移动
}else if(last == 4){ // 上一步向右移动
tp = tp - 2; // 不让其向左移动
}
return tp;
}

int Judge(int *arr1, int *arr2){
for(int i = 0; i < 9; i++){
if(arr1[i] != arr2[i]){
return 0;
}
}
return 1;
}

void Print(Data data){
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
std::cout << data.data[i * 3 + j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}

int main(){
Data originalData, targetArray;
int *arraytest1 = new int[9];
int *arraytest2 = new int[9];
originalData.step = 0;
std::cout << "请输入原始数据:" << std::endl;
for(int i = 0; i < 9; i++){
std::cin >> originalData.data[i];
}
std::cout << "请输入变换后数据:" << std::endl;
for(int i = 0; i < 9; i++){
std::cin >> targetArray.data[i];
}
// 数组输到arraytest
for(int i = 0; i < 9; i++){
arraytest1[i] = originalData.data[i];
arraytest2[i] = targetArray.data[i];
}
// 判断问题是否有解
int cnt1 = 0, cnt2 = 0;
for(int i = 0; i < 9; i++){
if(arraytest1[i] == 0){
continue;
}
for(int j = i - 1; j >= 0; j--){
if(arraytest1[j] > arraytest1[i]){
cnt1++;
}
}
}
for(int i = 0; i < 9; i++){
if(arraytest2[i] == 0){
continue;
}
for(int j = i - 1; j >= 0; j--){
if(arraytest2[j] > arraytest2[i]){
cnt2++;
}
}
}
if(cnt1%2 != cnt2%2){
std::cout << "E0: 输入有误!问题无解" << std::endl;
return 0;
}
// 排序
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
if(arraytest1[i] < arraytest1[j]){
int temp = arraytest1[i];
arraytest1[i] = arraytest1[j];
arraytest1[j] = temp;
}
}
}
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
if(arraytest2[i] < arraytest2[j]){
int temp = arraytest2[i];
arraytest2[i] = arraytest2[j];
arraytest2[j] = temp;
}
}
}
//判断排序后的数组是否相等
for(int i = 0; i < 9; i++){
if(arraytest1[i] != arraytest2[i]){
std::cout << "E1: 输入有误!请检查输入" << std::endl;
return 0;
}
}
delete[] arraytest1;
delete[] arraytest2;
clock_t start, finish;
double Total_time;
start = clock();
std::queue<Data> q;
q.push(originalData);
int action = 0;
Data temp;
while(true){ // 没必要设置成!q.empty(),只要循环继续就不可避免增加队列中的数据
temp = q.front();
q.pop();
// std::cout << "==========当前取出的元素:=========" << std::endl;
// Print(temp);
if(Judge(temp.data, targetArray.data)){
std::cout << "找到了!需要" << temp.step << "步" << std::endl;
break;
}
int i = 0; // 找到空(0)位置
for(i = 0; i < 9; i++){
if(temp.data[i] == 0){
break;
}
}
int nextAction = GetNextAction(temp);
if(nextAction>=8){
int arrayList[9];
for(int j = 0; j < 9; j++){
arrayList[j] = temp.data[j];
}
arrayList[i] = arrayList[i-3];
arrayList[i-3] = 0;
Data nextData;
for(int j = 0; j < 9; j++){
nextData.data[j] = arrayList[j];
}
nextData.step = temp.step + 1;
nextData.last = 1;
for(int j = 0; j < temp.step; j++){
nextData.action[j] = temp.action[j];
}
nextData.action[temp.step] = 1;
q.push(nextData);
// std::cout << "上nextData" << std::endl;
// Print(nextData);
}
if(nextAction%8>=4){
int arrayList[9];
for(int j = 0; j < 9; j++){
arrayList[j] = temp.data[j];
}
arrayList[i] = arrayList[i+3];
arrayList[i+3] = 0;
Data nextData;
for(int j = 0; j < 9; j++){
nextData.data[j] = arrayList[j];
}
nextData.step = temp.step + 1;
nextData.last = 2;
for(int j = 0; j < temp.step; j++){
nextData.action[j] = temp.action[j];
}
nextData.action[temp.step] = 2;
q.push(nextData);
// std::cout << "下nextData" << std::endl;
// Print(nextData);
}
if(nextAction%8%4>=2){
int arrayList[9];
for(int j = 0; j < 9; j++){
arrayList[j] = temp.data[j];
}
arrayList[i] = arrayList[i-1];
arrayList[i-1] = 0;
Data nextData;
for(int j = 0; j < 9; j++){
nextData.data[j] = arrayList[j];
}
nextData.step = temp.step + 1;
nextData.last = 3;
for(int j = 0; j < temp.step; j++){
nextData.action[j] = temp.action[j];
}
nextData.action[temp.step] = 3;
q.push(nextData);
// std::cout << "左nextData" << std::endl;
// Print(nextData);
}
if(nextAction%8%4%2>=1){
int arrayList[9];
for(int j = 0; j < 9; j++){
arrayList[j] = temp.data[j];
}
arrayList[i] = arrayList[i+1];
arrayList[i+1] = 0;
Data nextData;
for(int j = 0; j < 9; j++){
nextData.data[j] = arrayList[j];
}
nextData.step = temp.step + 1;
nextData.last = 4;
for(int j = 0; j < temp.step; j++){
nextData.action[j] = temp.action[j];
}
nextData.action[temp.step] = 4;
q.push(nextData);
// std::cout << "右nextData" << std::endl;
// Print(nextData);
}

}
finish = clock();
// 输出结果
int steps = temp.step;
std::cout << "步骤为:" << std::endl;
int *result = new int[temp.step];
for(int i = 0; i < temp.step; i++){
result[i] = temp.action[i];
}
Print(originalData);
int tempArray[9];
for(int i = 0; i < 9; i++){
tempArray[i] = originalData.data[i];
}
int position;
for(position = 0; position < 9; position++){
if(tempArray[position] == 0){
break;
}
}
for(int i = 0; i < temp.step; i++){
if(result[i] == 1){
tempArray[position] = tempArray[position-3];
tempArray[position-3] = 0;
position -= 3;
}else if(result[i] == 2){
tempArray[position] = tempArray[position+3];
tempArray[position+3] = 0;
position += 3;
}else if(result[i] == 3){
tempArray[position] = tempArray[position-1];
tempArray[position-1] = 0;
position -= 1;
}else if(result[i] == 4){
tempArray[position] = tempArray[position+1];
tempArray[position+1] = 0;
position += 1;
}else{
std::cout << "E2: 计算错误!请重试" << std::endl;
}
for(int j = 0; j < 3; j++){
for(int k = 0; k < 3; k++){
std::cout << tempArray[j*3+k] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
delete[] result;
std::cout << steps << "步,搜索用时:" << (double)(finish - start) / CLOCKS_PER_SEC << "s" << std::endl;
return 0;
}

C++运行结果

1
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
请输入原始数据:
1 2 3
0 4 5
6 7 8
请输入变换后数据:
0 2 3
1 7 5
4 6 8
找到了!需要5步
步骤为:
1 2 3
0 4 5
6 7 8

1 2 3
4 0 5
6 7 8

1 2 3
4 7 5
6 0 8

1 2 3
4 7 5
0 6 8

1 2 3
0 7 5
4 6 8

0 2 3
1 7 5
4 6 8

5步,搜索用时:0.001s

深度优先

C++

ATT: 此段代码存在bug,数据规模过大可能出现计算失败,空位在中间的时候为了节省内存可能不是最优先算法而将其先向上移动一格再进行计算

1
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
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
/*
* @Author: 转接
* @Date: 2022-03-10 12:24:48
* @LastEditors: 转接
* @LastEditTime: 2022-03-14 12:22:57
* @Description: 八数码问题深度优先求解
*/

#include <iostream>
#include <stack>
#include <algorithm>
#include <time.h>

// 数据
typedef struct data{
int data[9];
int step;
}Data;

// 链树
typedef struct NodeTag{
Data data;
int childNum;
NodeTag *father; // 父结点
NodeTag *child1; // 子结点1
NodeTag *child2; // 子结点2
NodeTag *child3; // 子结点3
int lastFunction = 0; // 上一个功能 上下左右 1234
int skip = 0; // 回溯到该结点的使用次数
int back = 0; // 是否回溯到该结点过
}NodeTag, *NodeTree;

// 链表存储回溯结点
typedef struct NodeLink{
NodeTree node; // 溯结点
NodeLink *next;
}NodeLink, *NodeLinkList;

int childNum[] = { // 子结点数量
1,2,1,
2,3,2,
1,2,1
/*
1,2,3,
4,5,6,
7,8,9
*/
};
int tempPosition[9][2] = { // 位置 上下左右
{0, 5}, // 0号位 0 1 0 1 = 5
{1, 7}, // 1号位 0 1 1 1 = 7
{2, 6}, // 2号位 0 1 1 0 = 6
{3, 13}, // 3号位 1 1 0 1 = 13
{4, 15}, // 4号位 1 1 1 1 = 15
{5, 14}, // 5号位 1 1 1 0 = 14
{6, 9}, // 6号位 1 0 0 1 = 9
{7, 11}, // 7号位 1 0 1 1 = 11
{8, 10}, // 8号位 1 0 1 0 = 10
}; // 上tempPosition[i][1]>=8 下tempPosition[i][1]%8>=4 左tempPosition[i][1]%8%4>=2 右tempPosition[i][1]%8%4%2>=1

// 初始化树 将原始数据originalData存入第一个结点
int InitTree(NodeTree &tree, Data originalData){
tree = new NodeTag;
tree->data = originalData;
tree->childNum = 0;
int i = 0;
for(i = 0; i < 9; i++){
if(tree->data.data[i] == 0){
tree->childNum = childNum[i]+1; // 设置子结点数量
}
}
tree->father = NULL;
tree->child1 = NULL;
tree->child2 = NULL;
tree->child3 = NULL;
tree->lastFunction = 0;
return i-1; // 将0的位置返回
}

// 插入结点到树
int InsertNode(NodeTree &tree, NodeTree &node){
if(tree->childNum == 1){ // 只能有一个子结点的结点
if(tree->child1 == NULL){
tree->child1 = node;
node->father = tree;
}else{
std::cout << "E2.1:数据规模错误" << std::endl;
return 1;
}
}else if(tree->childNum == 2){ // 只能有两个子结点的结点
if(tree->child1 == NULL){
tree->child1 = node;
node->father = tree;
}else if(tree->child2 == NULL){
tree->child2 = node;
node->father = tree;
}else{
std::cout << "E2.2:数据规模错误" << std::endl;
return 1;
}
}else if(tree->childNum == 3){ // 只能有三个子结点的结点
if(tree->child1 == NULL){
tree->child1 = node;
node->father = tree;
}else if(tree->child2 == NULL){
tree->child2 = node;
node->father = tree;
}else if(tree->child3 == NULL){
tree->child3 = node;
node->father = tree;
}else{
std::cout << "E2.3:数据规模错误" << std::endl;
return 1;
}
}
return 0;
}

// 初始化链表
void InitLink(NodeLinkList &link){
link = new NodeLink;
link->node = NULL;
link->next = NULL;
}

// 插入结点到链表
void InsertLink(NodeLinkList &link, NodeTree &node){
NodeLinkList temp = link;
while(temp->next != NULL){
temp = temp->next;
}
temp->next = new NodeLink;
temp->next->node = node;
temp->next->next = NULL;
}

// 在链表中查找结点是否存在
int SearchLink(NodeLinkList &link, NodeTree &node){
NodeLinkList temp = link;
while(temp->next != NULL){
if(temp->next->node == node){
return 1;
}
temp = temp->next;
}
return 0;
}

// 判断两Data中的数据是否相等
int judge(Data data1, Data data2){
for(int i = 0; i < 9; i++){
if(data1.data[i] != data2.data[i]){
return 0;
}
}
return 1;
}

// 规范输出结点中的数据
void Print(NodeTree tempNode){
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
std::cout << tempNode->data.data[i*3+j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}

int main(){
Data originalData, targetArray; // 原始数据 和 目标数据
int *arraytest1 = new int[9];
int *arraytest2 = new int[9];
originalData.step = 0; // 初始化步数
targetArray.step = -1;
int state = 1; // 程序错误状态
int middle = 0; // 判断0是否为中间结点
int deep;
std::cout << "请输入原始数据:" << std::endl;
for(int i = 0; i < 9; i++){
std::cin >> originalData.data[i];
}
if(originalData.data[4] == 0){
middle = 1;
originalData.data[4] = originalData.data[1];
originalData.data[1] = 0;
}
std::cout << "请输入变换后数据:" << std::endl;
for(int i = 0; i < 9; i++){
std::cin >> targetArray.data[i];
}
std::cout << "请输入搜索深度:" << std::endl;
std::cin >> deep;
clock_t start, finish;
double Total_time;
start = clock();
// 数组输到arraytest
for(int i = 0; i < 9; i++){
arraytest1[i] = originalData.data[i];
arraytest2[i] = targetArray.data[i];
}
// 判断问题是否有解
int cnt1 = 0, cnt2 = 0;
for(int i = 0; i < 9; i++){
if(arraytest1[i] == 0){
continue;
}
for(int j = i - 1; j >= 0; j--){
if(arraytest1[j] > arraytest1[i]){
cnt1++;
}
}
}
for(int i = 0; i < 9; i++){
if(arraytest2[i] == 0){
continue;
}
for(int j = i - 1; j >= 0; j--){
if(arraytest2[j] > arraytest2[i]){
cnt2++;
}
}
}
if(cnt1%2 != cnt2%2){
std::cout << "E0: 输入有误!问题无解" << std::endl;
return 0;
}
// 排序
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
if(arraytest1[i] < arraytest1[j]){
int temp = arraytest1[i];
arraytest1[i] = arraytest1[j];
arraytest1[j] = temp;
}
}
}
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
if(arraytest2[i] < arraytest2[j]){
int temp = arraytest2[i];
arraytest2[i] = arraytest2[j];
arraytest2[j] = temp;
}
}
}
//判断排序后的数组是否相等
for(int i = 0; i < 9; i++){
if(arraytest1[i] != arraytest2[i]){
state = 0;
}
}
free(arraytest1);
free(arraytest2);
NodeTree tree;
int tempNum = InitTree(tree, originalData);
if(tree->childNum == 0 && state){
std::cout << "E1:数据输入有误" << std::endl;
std::cout << "输入的数据要用表示空位,请检查输入!" << std::endl;
return 0;
}
NodeTree tempNode = tree; // 临时当前结点
NodeLinkList link; // 创建链表用来存储回溯结点
InitLink(link);
int step = 1;
while(true){
// 判断是否到达目标状态
if(judge(tempNode->data, targetArray) == 1){
if(middle){
tempNode->data.step++;
}
std::cout << "搜索完成,步数为:" << tempNode->data.step << std::endl;
break;
}
// 开始搜索
// 空格(0)向上移动
if(tempNode->data.step<deep && tempPosition[tempNum][1] >= 8 && tempNode->lastFunction != 4 && (tempNode->back == 0 --tempNode->skip <= 0)){
// 保证深度未达到目标深度,能向上交换的同时上一次不是向下移动,且不是跳过状态
Data tempData;
tempData.step = tempNode->data.step + 1;
for(int i = 0; i < 9; i++){ // 复制
tempData.data[i] = tempNode->data.data[i];
}
// 交换
tempData.data[tempNum] = tempData.data[tempNum-3];
tempData.data[tempNum-3] = 0;
tempNum = tempNum-3; // 标记交换后的位置
NodeTree node = new NodeTag;
node->data = tempData;
node->childNum = childNum[tempNum];
node->father = tempNode;
node->child1 = NULL;
node->child2 = NULL;
node->child3 = NULL;
node->lastFunction = 1;
if(InsertNode(tempNode, node)){
std::cout << "查找失败!尝试增加查找深度!" << std::endl;
return 0;
}
tempNode = node;

}
// 下
else if(tempNode->data.step<deep && tempPosition[tempNum][1]%8>=4 && tempNode->lastFunction != 1 && (tempNode->back == 0 --tempNode->skip <= 0)){
// 保证深度未达到目标深度,能向下交换的同时上一次不是向上移动,且不是跳过状态
Data tempData;
tempData.step = tempNode->data.step + 1;
for(int i = 0; i < 9; i++){ // 复制
tempData.data[i] = tempNode->data.data[i];
}
// 交换
tempData.data[tempNum] = tempData.data[tempNum+3];
tempData.data[tempNum+3] = 0;
tempNum = tempNum+3; // 标记交换后的位置
NodeTree node = new NodeTag;
node->data = tempData;
node->childNum = childNum[tempNum];
node->father = tempNode;
node->child1 = NULL;
node->child2 = NULL;
node->child3 = NULL;
node->lastFunction = 4;
if(InsertNode(tempNode, node)){
std::cout << "查找失败!尝试增加查找深度!" << std::endl;
return 0;
}
tempNode = node;
}
// 左
else if(tempNode->data.step<deep && tempPosition[tempNum][1]%8%4>=2 && tempNode->lastFunction != 3 && (tempNode->back == 0 --tempNode->skip <= 0)){
// 保证深度未达到目标深度,能向左交换的同时上一次不是向右移动,且不是跳过状态
Data tempData;
tempData.step = tempNode->data.step + 1;
for(int i = 0; i < 9; i++){ // 复制
tempData.data[i] = tempNode->data.data[i];
}
// 交换
tempData.data[tempNum] = tempData.data[tempNum-1];
tempData.data[tempNum-1] = 0;
tempNum = tempNum-1; // 标记交换后的位置
NodeTree node = new NodeTag;
node->data = tempData;
node->childNum = childNum[tempNum];
node->father = tempNode;
node->child1 = NULL;
node->child2 = NULL;
node->child3 = NULL;
node->lastFunction = 2;
if(InsertNode(tempNode, node)){
std::cout << "查找失败!尝试增加查找深度!" << std::endl;
return 0;
}
tempNode = node;
}
// 右
else if(tempNode->data.step<deep && tempPosition[tempNum][1]%8%4%2>=1 && tempNode->lastFunction != 2 && (tempNode->back == 0 --tempNode->skip <= 0)){
// 保证深度未达到目标深度,能向右交换的同时上一次不是向左移动,且不是跳过状态
Data tempData;
tempData.step = tempNode->data.step + 1;
for(int i = 0; i < 9; i++){ // 复制
tempData.data[i] = tempNode->data.data[i];
}
// 交换
tempData.data[tempNum] = tempData.data[tempNum+1];
tempData.data[tempNum+1] = 0;
tempNum = tempNum+1; // 标记交换后的位置
NodeTree node = new NodeTag;
node->data = tempData;
node->childNum = childNum[tempNum];
node->father = tempNode;
node->child1 = NULL;
node->child2 = NULL;
node->child3 = NULL;
node->lastFunction = 3;
if(InsertNode(tempNode, node)){
std::cout << "查找失败!尝试增加查找深度!" << std::endl;
return 0;
}
tempNode = node;
}
else{
do{
tempNode = tempNode->father;
if(tempNode->childNum == 2 && tempNode->child2 == NULL){
// 将结点插入链表
if(SearchLink(link, tempNode) == 0){
InsertLink(link, tempNode);
tempNode->skip++;
}
tempNode->skip++;
tempNode->back = 1;
step--;
break;
}else if(tempNode->childNum == 3 && tempNode->child3 == NULL){
if(SearchLink(link, tempNode) == 0){
InsertLink(link, tempNode);
tempNode->skip++;
}
tempNode->skip++;
tempNode->back = 1;
step--;
break;
}else{
continue;
}
}while(tempNode != tree);
int i = 0;
for(i = 0; i < 9; i++){
if(tempNode->data.data[i] == 0){
break;
}
}
tempNum = i;
}
// std::cout << "step: " << step << std::endl;
// Print(tempNode);
}
finish = clock();
int steps = tempNode->data.step;
// 判断是否搜索完成将结点压入栈中
std::stack <NodeTree> tempStack;
while(tempNode != tree){
tempStack.push(tempNode);
tempNode = tempNode->father;
}
// 打印输出栈
std::cout << "输出步骤:" << std::endl;
if(middle){ //如果最开始空格(0)位置在中间
tree->data.data[1]=tree->data.data[4];
tree->data.data[4]=0;
Print(tree);
tree->data.data[4]=tree->data.data[1];
tree->data.data[1]=0;
}
Print(tree);
while(!tempStack.empty()){
tempNode = tempStack.top();
tempStack.pop();
Print(tempNode);
}
std::cout << steps << "步,搜索用时:" << (double)(finish - start) / CLOCKS_PER_SEC << "s" << std::endl;
return 0;
}

C++运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
请输入原始数据:
1 2 3
4 5 6
7 8 0
请输入变换后数据:
1 2 3
4 5 6
0 7 8
请输入搜索深度:
3
搜索完成,步数为:2
输出步骤:
1 2 3
4 5 6
7 8 0

1 2 3
4 5 6
7 0 8

1 2 3
4 5 6
0 7 8

2步,搜索用时:0.002s

Python

1
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
'''
Author: 转接
Date: 2022-03-14 12:41:19
LastEditors: 转接
LastEditTime: 2022-03-14 14:16:59
Description: 八数码问题深度优先求解
'''

import numpy as np
import copy
from datetime import datetime

# 找到空位
def local(tempData):
a = np.array(tempData)
i,j = np.where(a == 0)
return i[0],j[0]

# 向上移动
def ToUp(tempData):
i,j = local(tempData)
arr = copy.deepcopy(tempData)
if i in (1,len(tempData)-1):
arr[i][j],arr[i-1][j] = arr[i-1][j],arr[i][j]
return arr

# 向下移动
def ToDown(tempData):
i,j = local(tempData)
arr = copy.deepcopy(tempData)
if i in (0,len(tempData)-2):
arr[i][j],arr[i+1][j] = arr[i+1][j],arr[i][j]
return arr

# 向左移动
def ToRight(tempData):
i,j = local(tempData)
arr = copy.deepcopy(tempData)
if j in (0,len(tempData)-2):
arr[i][j], arr[i][j+1] = arr[i][j+1],arr[i][j]
return arr
# 向右移动
def ToLeft(tempData):
i,j = local(tempData)
arr = copy.deepcopy(tempData)
if j in (1,len(tempData)-1):
arr[i][j],arr[i][j-1] = arr[i][j-1],arr[i][j]
return arr

# 格式化输出
def OutPrint(tempData):
for arr in tempData:
print(arr[0],arr[1],arr[2])
print()

# 定义一个节点类用于存放必要的数据
class Node:
def __init__(self,data,level,parent):
self.data=data
self.level=level
self.parent = parent


if __name__ == "__main__":
# 输入数据
originalData = [list(map(int,input("请输入原始数据:\n").split())), list(map(int,input().split())), list(map(int,input().split()))]
targetArray = [list(map(int,input("请输入变换后数据:\n").split())), list(map(int,input().split())), list(map(int,input().split()))]
list1 = []
list2 = []
# 数组输到list
for arr in originalData:
list1.append(arr[0])
list1.append(arr[1])
list1.append(arr[2])
for arr in targetArray:
list2.append(arr[0])
list2.append(arr[1])
list2.append(arr[2])
cnt1 = 0
cnt2 = 0
for i in range(0,9):
if i == 0:
continue
for j in range(i-1,0):
if i < list1[j]:
cnt1 = cnt1 + 1
for i in range(0,9):
if i == 0:
continue
for j in range(i-1,0):
if i < list2[j]:
cnt2 = cnt2 + 1
if cnt1%2 != cnt2%2:
print("E0: 输入有误!问题无解")
exit(0)
list1.sort()
list2.sort()
for i in range (0, 9):
if list1[i] != list2[i]:
print("E1: 输入有误!请检查输入")
exit(0)
Node0 = Node(originalData,0,"None")
deep_level = int(input("请输入搜索深度:"))
open_ = [Node0]
close = []
step = 0
steps = 0
start = datetime.now()
while len(open_) > 0:
step = step + 1
n = open_.pop(0)
close.append(n)
# 找到结果,则输出其最优路径
if n.data == targetArray:
print('搜索完毕!步骤为:')
result = []
result.append(n)
while n.parent!="None":
result.append(n.parent)
n = n.parent
steps = len(result)-1
for j in range(len(result)):
result_0 = result.pop(-1)
OutPrint(result_0.data)
break
else:
if n.level<=int(deep_level):
local(n.data)
Up = ToUp(n.data)
if Up not in [open_[i].data for i in range(len(open_))] and Up not in [close[i].data for i in range(len(close))] and Up is not None:
Node0 = Node(Up,n.level+1,n)
open_.insert(0,Node0)

Down = ToDown(n.data)
if Down not in [open_[i].data for i in range(len(open_))] and Down not in [close[i].data for i in range(len(close))] and Down is not None:
Node0 = Node(Down,n.level+1,n)
open_.insert(0,Node0)

Left = ToLeft(n.data)
if Left not in [open_[i].data for i in range(len(open_))] and Left not in [close[i].data for i in range(len(close))] and Left is not None:
Node0 = Node(Left,n.level+1,n)
open_.insert(0,Node0)

Right = ToRight(n.data)
if Right not in [open_[i].data for i in range(len(open_))] and Right not in [close[i].data for i in range(len(close))] and Right is not None:
Node0 = Node(Right,n.level+1,n)
open_.insert(0,Node0)
end = datetime.now()
print(steps,'步,搜索用时:', end - start)

Python运行结果

1
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
请输入原始数据:
1 2 3
0 4 5
6 7 8
请输入变换后数据:
0 2 3
1 7 5
4 6 8
请输入搜索深度:6
搜索完毕!步骤为:
1 2 3
0 4 5
6 7 8

1 2 3
4 0 5
6 7 8

1 2 3
4 7 5
6 0 8

1 2 3
4 7 5
0 6 8

1 2 3
0 7 5
4 6 8

0 2 3
1 7 5
4 6 8

5 步,搜索用时: 0:00:00.004012

启发式搜索

C++

1
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
/*
* @Author: 转接
* @Date: 2022-03-12 20:31:24
* @LastEditors: 转接
* @LastEditTime: 2022-03-13 19:01:10
* @Description: 八数码问题启发式搜索
*/

#include <iostream>
#include <stack>
#include <time.h>

// 创建链表
typedef struct Data{
int data[9]; // 存放数据
int value; // 存f(n)
int step; // 记录步数
int lastAction; // 上一步操作 上 下 左 右 1 2 3 4
Data *next; // 链表中下一个结点
Data *last; // 操作图中对应的上一个结点
}Data, *DataList;

int tempPosition[9][2] = { // 位置 上下左右
{0, 5}, // 0号位 0 1 0 1 = 5
{1, 7}, // 1号位 0 1 1 1 = 7
{2, 6}, // 2号位 0 1 1 0 = 6
{3, 13}, // 3号位 1 1 0 1 = 13
{4, 15}, // 4号位 1 1 1 1 = 15
{5, 14}, // 5号位 1 1 1 0 = 14
{6, 9}, // 6号位 1 0 0 1 = 9
{7, 11}, // 7号位 1 0 1 1 = 11
{8, 10}, // 8号位 1 0 1 0 = 10
};

int distance[9][9] = { // 位置 上下左右
{0, 1, 2, 1, 2, 3, 2, 3, 4},
{1, 0, 1, 2, 1, 2, 3, 2, 3},
{2, 1, 0, 3, 2, 1, 4, 3, 2},
{1, 2, 3, 0, 1, 2, 1, 2, 3},
{2, 1, 2, 1, 0, 1, 2, 1, 2},
{3, 2, 1, 2, 1, 0, 3, 2, 1},
{2, 3, 4, 1, 2, 3, 0, 1, 2},
{3, 2, 3, 2, 1, 2, 1, 0, 1},
{4, 3, 2, 3, 2, 1, 2, 1, 0},
};

int GetNextAction(Data data){
int *temp = data.data;
int i = 0;
for(i = 0; i < 9; i++){
if(temp[i] == 0){
break;
}
}
int tp = tempPosition[i][1];
int last = data.lastAction;
if(last == 1){ // 上一步向上移动
tp = tp - 4; // 不让其向下移动
}else if(last == 2){ // 上一步向下移动
tp = tp - 8; // 不让其向上移动
}else if(last == 3){ // 上一步向左移动
tp = tp - 1; // 不让其向右移动
}else if(last == 4){ // 上一步向右移动
tp = tp - 2; // 不让其向左移动
}
return tp;
}

int Judge(int *arr1, int *arr2){
for(int i = 0; i < 9; i++){
if(arr1[i] != arr2[i]){
return 0;
}
}
return 1;
}

void Print(Data data){
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
std::cout << data.data[i * 3 + j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}

// 初始化链表
void InitList(DataList &head){
head = (Data *)malloc(sizeof(Data));
head->lastAction = 0;
head->next = NULL;
head->last = NULL;
}

int Gn(int *arr){
int sum = 0;
for(int i = 0; i < 9; i++){
sum += distance[arr[i]][i];
}
return sum;
}

// 按照f(n)值的大小插入链表 链表 数组 价值 上一步操作
void InsertList(DataList &head, int *arr, int value, int lastAction){
Data *temp = head;
Data *newNode = (Data *)malloc(sizeof(Data));

for(int i = 0; i < 9; i++){
newNode->data[i] = arr[i];
}
newNode->value = value;
newNode->step = head->step + 1;
newNode->next = NULL;
newNode->last = head;
// if(lastAction == 0){
// newNode->last = NULL;
// }
while(temp->next != NULL){
if(temp->next->value < value){
temp = temp->next;
}else{
break;
}
}
newNode->next = temp->next;
temp->next = newNode;
}

int main(){
int *originalData = new int[9];
int *targetArray = new int[9];
int *arraytest1 = new int[9];
int *arraytest2 = new int[9];
std::cout << "请输入原始数据:" << std::endl;
for(int i = 0; i < 9; i++){
std::cin >> originalData[i];
}
std::cout << "请输入变换后数据:" << std::endl;
for(int i = 0; i < 9; i++){
std::cin >> targetArray[i];
}
// 复制数组到arraytest
for(int i = 0; i < 9; i++){
arraytest1[i] = originalData[i];
arraytest2[i] = targetArray[i];
}
// 判断问题是否有解
int cnt1 = 0, cnt2 = 0;
for(int i = 0; i < 9; i++){
if(arraytest1[i] == 0){
continue;
}
for(int j = i - 1; j >= 0; j--){
if(arraytest1[j] > arraytest1[i]){
cnt1++;
}
}
}
for(int i = 0; i < 9; i++){
if(arraytest2[i] == 0){
continue;
}
for(int j = i - 1; j >= 0; j--){
if(arraytest2[j] > arraytest2[i]){
cnt2++;
}
}
}
if(cnt1%2 != cnt2%2){
std::cout << "E0: 输入有误!问题无解" << std::endl;
return 0;
}
// 排序
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
if(arraytest1[i] < arraytest1[j]){
int temp = arraytest1[i];
arraytest1[i] = arraytest1[j];
arraytest1[j] = temp;
}
}
}
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
if(arraytest2[i] < arraytest2[j]){
int temp = arraytest2[i];
arraytest2[i] = arraytest2[j];
arraytest2[j] = temp;
}
}
}
//判断排序后的数组是否相等
for(int i = 0; i < 9; i++){
if(arraytest1[i] != arraytest2[i]){
std::cout << "E1: 输入有误!请检查输入" << std::endl;
return 0;
}
}
delete[] arraytest1;
delete[] arraytest2;
clock_t start, finish;
double Total_time;
start = clock();
DataList head; // 定义链表存放数据
InitList(head); // 初始化链表 即创建头节点
head->step = -1;
DataList temp = head;
InsertList(head, originalData, Gn(originalData), 0); // 将原始数据结点存放到头节点后的数据区域
while(true){
temp = temp->next;
if(Judge(targetArray, temp->data)){
std::cout << "找到了!需要" << temp->step << "步" << std::endl;
break;
}
int i = 0; // 找到空(0)位置
for(i = 0; i < 9; i++){
if(temp->data[i] == 0){
break;
}
}
// int tempArraylist[9];
// for(int j = 0; j < 9; j++){
// tempArraylist[j] = temp->next->data[j];
// }
int nextAction = GetNextAction(*temp);
if(nextAction>=8){
int arrayList[9];
for(int j = 0; j < 9; j++){
arrayList[j] = temp->data[j];
}
arrayList[i] = arrayList[i-3];
arrayList[i-3] = 0;
InsertList(temp, arrayList, Gn(arrayList)+temp->step, 1);
}
if(nextAction%8>=4){
int arrayList[9];
for(int j = 0; j < 9; j++){
arrayList[j] = temp->data[j];
}
arrayList[i] = arrayList[i+3];
arrayList[i+3] = 0;
InsertList(temp, arrayList, Gn(arrayList)+temp->step, 2);
}
if(nextAction%8%4>=2){
int arrayList[9];
for(int j = 0; j < 9; j++){
arrayList[j] = temp->data[j];
}
arrayList[i] = arrayList[i-1];
arrayList[i-1] = 0;
InsertList(temp, arrayList, Gn(arrayList)+temp->step, 3);
}
if(nextAction%8>=4){
int arrayList[9];
for(int j = 0; j < 9; j++){
arrayList[j] = temp->data[j];
}
arrayList[i] = arrayList[i+1];
arrayList[i+1] = 0;
InsertList(temp, arrayList, Gn(arrayList)+temp->step, 4);
}
}
finish = clock();
std::stack<int *>s;
int steps = temp->step;
std::cout << "步骤为:" << std::endl;
while(temp->last != NULL){
s.push(temp->data);
temp = temp->last;
}

while(!s.empty()){
int *arr = s.top();
s.pop();
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
std::cout << arr[i * 3 + j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
std::cout << steps << "步,搜索用时:" << (double)(finish - start) / CLOCKS_PER_SEC << "s" << std::endl;
return 0;
}

C++运行结果

1
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
请输入原始数据:
1 2 3
0 4 5
6 7 8
请输入变换后数据:
0 2 3
1 7 5
4 6 8
找到了!需要5步
步骤为:
1 2 3
0 4 5
6 7 8

1 2 3
4 0 5
6 7 8

1 2 3
4 7 5
6 0 8

1 2 3
4 7 5
0 6 8

1 2 3
0 7 5
4 6 8

0 2 3
1 7 5
4 6 8

5步,搜索用时:0.005s

代码说明

判断可移动方向变量:tempPosition

1
2
3
4
5
6
7
8
9
10
11
int tempPosition[9][2] = { // 位置 上下左右 
{0, 5}, // 0号位 0 1 0 1 = 5
{1, 7}, // 1号位 0 1 1 1 = 7
{2, 6}, // 2号位 0 1 1 0 = 6
{3, 13}, // 3号位 1 1 0 1 = 13
{4, 15}, // 4号位 1 1 1 1 = 15
{5, 14}, // 5号位 1 1 1 0 = 14
{6, 9}, // 6号位 1 0 0 1 = 9
{7, 11}, // 7号位 1 0 1 1 = 11
{8, 10}, // 8号位 1 0 1 0 = 10
};

通过四个二进制数字来表示四个方向移动(交换)的可行性再将二进制数字转换为十进制数字存在二维数组中。通过判断其值来判断能否向指定方向移动。如能向上tempPosition[i][1]>=8能向下tempPosition[i][1]%8>=4能向左tempPosition[i][1]%8%4>=2能向右tempPosition[i][1]%8%4%2>=1


判断两个点之间距离变量:distance

1
2
3
4
5
6
7
8
9
10
11
int distance[9][9] = { // 位置 上下左右 
{0, 1, 2, 1, 2, 3, 2, 3, 4},
{1, 0, 1, 2, 1, 2, 3, 2, 3},
{2, 1, 0, 3, 2, 1, 4, 3, 2},
{1, 2, 3, 0, 1, 2, 1, 2, 3},
{2, 1, 2, 1, 0, 1, 2, 1, 2},
{3, 2, 1, 2, 1, 0, 3, 2, 1},
{2, 3, 4, 1, 2, 3, 0, 1, 2},
{3, 2, 3, 2, 1, 2, 1, 0, 1},
{4, 3, 2, 3, 2, 1, 2, 1, 0},
};

通过**distance[i][j]**来表示i号位置和j号位置的距离,进而去计算启发函数中的g(n)。


判断问题是否有解

1
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
// 判断问题是否有解
int cnt1 = 0, cnt2 = 0;
for(int i = 0; i < 9; i++){
if(arraytest1[i] == 0){
continue;
}
for(int j = i - 1; j >= 0; j--){
if(arraytest1[j] > arraytest1[i]){
cnt1++;
}
}
}
for(int i = 0; i < 9; i++){
if(arraytest2[i] == 0){
continue;
}
for(int j = i - 1; j >= 0; j--){
if(arraytest2[j] > arraytest2[i]){
cnt2++;
}
}
}
if(cnt1%2 != cnt2%2){
std::cout << "E0: 输入有误!问题无解" << std::endl;
return 0;
}
  • 逆序:即在某个数字的前面比它大的数字个数。

左右移动,不影响逆序数;上下移动,逆序数加2或者减2。即如果初始状态能通过移动空格(0)来到达移动目标状态,则初始状态和目标状态的逆序数应该为同奇同偶


广度优先代码优化思路 (DBFS)

可以将循环代码优化,使得不仅仅从原始数据广度优先开始搜索,也可以同时从目标数据广度优先进行搜索,能缩短约一半时间(双向广度优先算法DBFS)


启发式函数 f(n) = g(n) + h(n) 的分析

  1. g(n)=0,一种极端情况如果g(n)=0,则只有h(n)起作用,此时A*演变成贪心算法。
  2. h(n)=0,一种极端情况如果h(n)=0,则只有g(n)起作用,此时A*演变成Dijkstra算法,这保证能找到最短路径,但效率不到。
  3. h(n)<实际代价 如果h(n)经常都比从n移动到目标的实际代价小(或者相等),则A*保证能找到一条最短路径h(n)越小,A扩展的结点越多,运行就越慢
  4. h(n)=实际代价 如果h(n)精确地等于从n移动到目标的实际代价,则A*将会仅仅寻找最佳路径而不扩展别的任何结点,这会运行得非常快。尽管这不可能在所有情况下发生,你仍可以在一些特殊情况下让它们精确地相等(指让h(n)精确地等于实际代价)。只要提供完美的信息,A*就会运行得很完美。
  5. h(n)>实际代价 如果h(n)有时比从n移动到目标的实际代价大,则A*不能保证找到一条最短路径,但它运行得更快
  6. h(n)>>实际代价,即h(n)>>g(n),则只有h(n)起作用,A*演变成BFS算法

八数码问题
https://blog.zhuanjie.ltd/2022/03/10/eight-digital-problems/
作者
转接
发布于
2022年3月10日
许可协议