八数码问题,A*算法,启发函数

八数码难题:设问题的初始状态为S0和目标状态Sg,如图所示。请用A*算法求解。(定义两种以上的评估函数,分别给出搜索树和计算过程,并进行不同评估函数的对比分析)

初始状态                     目标状态

2

8

3

 

1

2

3

1

 

4

 

8

 

4

7

6

5

 

7

6

5

启发函数(3种启发函数,可以比较优劣):

 1 def Heuristic(self, list_end):         # 启发函数, list_end是目标状态的八数码
 2     self.key = self.h = 0
 3     '''启发函数中h(n)的求解'''
 4     # ''' 1. n状态时,不在目标状态的数码个数
 5     for i in range(9):
 6         self.h += 0 if self.digits[i] == list_end[i] else 1
 7     # '''
 8 
 9     # '''2. n状态时,不在目标状态的数码移动到目标状态时的距离--曼哈顿距离
10     for i in range(1, 9):
11         idx_end = list_end.index(i)
12         idx_self = self.digits.index(i)
13         self.h += abs(idx_end - idx_self) // 3 + abs(idx_end - idx_self - (idx_end - idx_self) // 3 * 3)
14     # '''
15     
16     # '''3. 数码排成一行,n状态时,不在目标状态的数码移动到目标状态时的距离
17     for i in range(1, 9):
18         idx_end = list_end.index(i)
19         idx_self = self.digits.index(i)
20         self.h += abs(idx_end - idx_self)
21     # '''
22     self.key = self.h + self.d          # 启发函数

利用优先队列求解八数码问题:

结构体:包含启发函数,数码状态,以及解的路径。选用其中一种启发函数。

 1 # 设计八数码问题的数据结构
 2 class Eight_Node:
 3     def __init__(self):
 4         self.key = 0        # 启发函数 key = f(n) = d(n) + h(n)
 5         self.h = 0          # h(n),根据Heuristic(self, list_end)函数求解h(n) 与 f(n)
 6         self.d = 0          # 树高
 7         self.digits = list()*9          # 矩阵,一行表示
 8         self.solutionTree = list()      # 解的过程
 9 
10     def __gt__(self, other):
11         return self.key > other.key
12 
13     def Heuristic(self, list_end):         # 启发函数, list_end是目标状态的八数码
14         self.key = self.h = 0
15         '''启发函数中h(n)的求解'''
16         ''' 1. n状态时,不在目标状态的数码个数
17         for i in range(9):
18             self.h += 0 if self.digits[i] == list_end[i] else 1
19         '''
20 
21         '''2. n状态时,不在目标状态的数码移动到目标状态时的距离--曼哈顿距离
22         for i in range(1, 9):
23             idx_end = list_end.index(i)
24             idx_self = self.digits.index(i)
25             self.h += abs(idx_end - idx_self) // 3 + abs(idx_end - idx_self - (idx_end - idx_self) // 3 * 3)
26         '''
27 
28         # '''3. 数码排成一行,n状态时,不在目标状态的数码移动到目标状态时的距离
29         for i in range(1, 9):
30             idx_end = list_end.index(i)
31             idx_self = self.digits.index(i)
32             self.h += abs(idx_end - idx_self)
33         # '''
34         self.key = self.h + self.d          # 启发函数

解函数:

 1 def Solve_Eight_Node(start_list1, end_list2):                 # 函数求解
 2     start_node = Eight_Node()           # 初始状态
 3     end_node = Eight_Node()             # 目标状态
 4     # 初始状态start_node, 目标状态end_node,构建八数码
 5     start_node.digits = start_list1
 6     start_node.solutionTree.append(start_node.digits)
 7     end_node.digits = end_list2
 8     start_node.Heuristic(end_node.digits)
 9     # close表
10     dic = [[-1, 0], [1, 0], [0, -1], [0, 1]]  # 上、下、左、右--数码移动
11     close_base = list()  # close_base记录所有使用过的状态,也可用于去重
12     close_base.append(''.join(str(i) for i in start_node.digits))
13 
14     # 优先队列,以启发函数升序
15     priQu = PriorityQueue()  # open表,优先队列实现
16     priQu.put(start_node)
17     # 开始搜索
18     conclusion = Eight_Node()  # 记录搜索到的结果
19     while not priQu.empty():
20         node = priQu.get()
21         if node.h == 0:  # 查找到目标状态,结束,启发函数为0,和目标状态一样
22             conclusion = node
23             break
24         # 数码进行移动,处理四个方向
25         idx = node.digits.index(0)
26         x = idx // 3  # 0 于八数码位置的坐标(0,0) <= (x,y) <= (2,2)
27         y = idx - 3 * x
28         for i in range(4):  # 0,1,2,3,分别和上下左右的方块交换
29             new_x = x + dic[i][0]
30             new_y = y + dic[i][1]
31             if 0 <= new_x <= 2 and 0 <= new_y <= 2:  # 未超过边界
32                 new_node = Eight_Node()
33                 new_node.digits = copy.deepcopy(node.digits)  # 深度复制八数码矩阵
34                 new_node.solutionTree = copy.deepcopy(node.solutionTree)  # 深度复制八数码解过程
35                 new_node.digits[idx] = new_node.digits[new_x * 3 + new_y]  # 数码移动
36                 new_node.digits[new_x * 3 + new_y] = 0
37                 new_node.d = node.d + 1  # 树高加一
38                 new_node.Heuristic(end_node.digits)  # 计算key,h,启发函数
39                 new_node.solutionTree.append(new_node.digits)  # 解过程增加一个状态
40                 node_str = ''.join(str(j) for j in new_node.digits)
41                 if node_str not in close_base:  # 判重
42                     close_base.append(node_str)
43                     priQu.put(new_node)
44     return conclusion

测试:

解空间树:

全部代码;

  1 from queue import PriorityQueue
  2 import copy
  3 
  4 # 设计八数码问题的数据结构
  5 class Eight_Node:
  6     def __init__(self):
  7         self.key = 0        # 启发函数 key = f(n) = d(n) + h(n)
  8         self.h = 0          # h(n),根据Heuristic(self, list_end)函数求解h(n) 与 f(n)
  9         self.d = 0          # 树高
 10         self.digits = list()*9          # 矩阵,一行表示
 11         self.solutionTree = list()      # 解的过程
 12 
 13     def __gt__(self, other):
 14         return self.key > other.key
 15 
 16     def Heuristic(self, list_end):         # 启发函数, list_end是目标状态的八数码
 17         self.key = self.h = 0
 18         '''启发函数中h(n)的求解'''
 19         ''' 1. n状态时,不在目标状态的数码个数
 20         for i in range(9):
 21             self.h += 0 if self.digits[i] == list_end[i] else 1
 22         '''
 23 
 24         '''2. n状态时,不在目标状态的数码移动到目标状态时的距离--曼哈顿距离
 25         for i in range(1, 9):
 26             idx_end = list_end.index(i)
 27             idx_self = self.digits.index(i)
 28             self.h += abs(idx_end - idx_self) // 3 + abs(idx_end - idx_self - (idx_end - idx_self) // 3 * 3)
 29         '''
 30 
 31         # '''3. 数码排成一行,n状态时,不在目标状态的数码移动到目标状态时的距离
 32         for i in range(1, 9):
 33             idx_end = list_end.index(i)
 34             idx_self = self.digits.index(i)
 35             self.h += abs(idx_end - idx_self)
 36         # '''
 37         self.key = self.h + self.d          # 启发函数
 38 
 39 
 40 def Solve_Eight_Node(start_list1, end_list2):                 # 函数求解
 41     start_node = Eight_Node()           # 初始状态
 42     end_node = Eight_Node()             # 目标状态
 43     # 初始状态start_node, 目标状态end_node,构建八数码
 44     start_node.digits = start_list1
 45     start_node.solutionTree.append(start_node.digits)
 46     end_node.digits = end_list2
 47     start_node.Heuristic(end_node.digits)
 48     # close表
 49     dic = [[-1, 0], [1, 0], [0, -1], [0, 1]]  # 上、下、左、右--数码移动
 50     close_base = list()  # close_base记录所有使用过的状态,也可用于去重
 51     close_base.append(''.join(str(i) for i in start_node.digits))
 52 
 53     # 优先队列,以启发函数升序
 54     priQu = PriorityQueue()  # open表,优先队列实现
 55     priQu.put(start_node)
 56     # 开始搜索
 57     conclusion = Eight_Node()  # 记录搜索到的结果
 58     while not priQu.empty():
 59         node = priQu.get()
 60         if node.h == 0:  # 查找到目标状态,结束,启发函数为0,和目标状态一样
 61             conclusion = node
 62             break
 63         # 数码进行移动,处理四个方向
 64         idx = node.digits.index(0)
 65         x = idx // 3  # 0 于八数码位置的坐标(0,0) <= (x,y) <= (2,2)
 66         y = idx - 3 * x
 67         for i in range(4):  # 0,1,2,3,分别和上下左右的方块交换
 68             new_x = x + dic[i][0]
 69             new_y = y + dic[i][1]
 70             if 0 <= new_x <= 2 and 0 <= new_y <= 2:  # 未超过边界
 71                 new_node = Eight_Node()
 72                 new_node.digits = copy.deepcopy(node.digits)  # 深度复制八数码矩阵
 73                 new_node.solutionTree = copy.deepcopy(node.solutionTree)  # 深度复制八数码解过程
 74                 new_node.digits[idx] = new_node.digits[new_x * 3 + new_y]  # 数码移动
 75                 new_node.digits[new_x * 3 + new_y] = 0
 76                 new_node.d = node.d + 1  # 树高加一
 77                 new_node.Heuristic(end_node.digits)  # 计算key,h,启发函数
 78                 new_node.solutionTree.append(new_node.digits)  # 解过程增加一个状态
 79                 node_str = ''.join(str(j) for j in new_node.digits)
 80                 if node_str not in close_base:  # 判重
 81                     close_base.append(node_str)
 82                     priQu.put(new_node)
 83     return conclusion
 84 
 85 
 86 if __name__ == "__main__":
 87     start_list = list(map(int, input("请输入处于初始状态的八数码(一行输入即可):").split(",")))
 88     end_list = list(map(int, input("请输入处于目标状态的八数码(一行输入即可):").split(",")))
 89     result = Solve_Eight_Node(start_list, end_list)
 90     print("八数码问题的求解:")
 91     print("初始状态      目标状态")
 92     for i in range(3):
 93         print(start_list[3 * i:3 * i + 3], '  ', end_list[3 * i:3 * i + 3])
 94     print("求解树:")
 95     index_i = 0
 96     for li in result.solutionTree:
 97         print("step # %d :" % index_i)
 98         for i in range(3):
 99             print(li[3 * i:3 * i + 3])
100         print("-----------")
101         index_i += 1
102 # 2,8,3,1,0,4,7,6,5   [0,1,2,3,4,5,6,7,8]    [1,2,3,8,0,4,7,6,5]    [0,1,2,3,4,5,6,7,8]
103 # 1,2,3,8,0,4,7,6,5   [8,7,6,5,4,3,2,1,0]    [2,1,6,4,0,8,7,5,3]    [8,7,6,5,4,3,2,1,0]
View Code

2021-06-04

原文地址:https://www.cnblogs.com/2015-16/p/14850950.html