zoukankan      html  css  js  c++  java
  • 八数码问题,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

  • 相关阅读:
    Python 描述符(descriptor) 杂记
    Celery 使用简介
    异步任务神器 Celery 简明笔记
    高性能框架gevent和gunicorn在web上的应用及性能测试
    Flask + Gunicorn + Nginx 部署
    Mysql查看最大连接数和修改最大连接数
    配置 influxDB 鉴权及 HTTP API 写数据的方法
    Java 字符串拼接 五种方法的性能比较分析 从执行100次到90万次
    linux端口开放指定端口的两种方法
    java自带的监控工具VisualVM一
  • 原文地址:https://www.cnblogs.com/2015-16/p/14850950.html
Copyright © 2011-2022 走看看