zoukankan      html  css  js  c++  java
  • 广度优先搜索-八数码问题

    八数码问题(Eight):八数码问题是人工智能中的经典问题
    有一个3*3的棋盘,其中有0-8共9个数字,0表示空格,
    其他的数字可以和0交换位置。求由初始状态
    到达目标状态
    8 2 3 1 2 3
    1 4 6 ----> 4 5 6
    5 7 0 7 8 0
    的步数最少的解。

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

    输入格式:输入初始状态,一行九个数字,空格用0表示
    123406758
    823146570
    输出格式:只有一行,该行只有一个数字,表示从初始状态到目标状态需要的
    最少移动次数(测试数据中无特殊无法到达目标状态数据)
    2
    18
    https://www.cnblogs.com/czc1999/p/10428066.html
    https://blog.csdn.net/yangysc/article/details/50710439

    python代码实现:
      1 # 目标状态
      2 goal_status = 123456780
      3 # 四种移动方向
      4 moves = ["u", "d", "r", "l"]
      5 myQueue = [0 for i in range(400000)]  # 状态队列,状态总数362880,对每种状态进行插入或者移除
      6 qHead = 0  # 队头指针
      7 qTail = 1  # 队尾指针
      8 
      9 
     10 class Node:
     11     status = 0  # 状态
     12     father = 0  # 父节点指针,即myQueue的下标
     13     move = ""  # 父节点到本节点的移动方式 u/d/r/l
     14 
     15     def __init__(self, s, f, m):
     16         self.status = s
     17         self.father = f
     18         self.move = m
     19 
     20 
     21 # 求从status经过move移动后得到的新状态。若移动不可行则返回-1
     22 def  NewStatus(status, move):
     23     zeroPos = 0  # 字符'0'的位置
     24     # 不足9位时,前面补0
     25     tmp = str(status).zfill(9)
     26     zeroPos = tmp.find('0')
     27     temp_list = list(tmp)
     28     if move == "u":
     29         if zeroPos - 3 < 0:  # 空格在第一行
     30             return -1
     31         else:
     32             temp_list[zeroPos] = temp_list[zeroPos - 3]
     33             temp_list[zeroPos - 3] = '0'
     34     elif move == "d":
     35         if zeroPos + 3 > 8:  # 空格在第三行
     36             return -1
     37         else:
     38             temp_list[zeroPos] = temp_list[zeroPos + 3]
     39             temp_list[zeroPos + 3] = '0'
     40     elif move == "l":
     41         if zeroPos % 3 == 0:  # 空格在第一列
     42             return -1
     43         else:
     44             temp_list[zeroPos] = temp_list[zeroPos-1]
     45             temp_list[zeroPos-1] = '0'
     46     elif move == "r":
     47         if zeroPos % 3 == 2:  # 空格在第三列
     48             return -1
     49         else:
     50             temp_list[zeroPos] = temp_list[zeroPos+1]
     51             temp_list[zeroPos+1] = '0'
     52     tmp = "".join(temp_list)
     53     return int(tmp)
     54 
     55 
     56 def bfs(status):
     57     global qHead, qTail, goal_status, moves
     58     # 把每个状态都存入该set中,set有判重的功能
     59     expanded = set()
     60     # 初始状态放入队头
     61     myQueue[qHead] = Node(status, -1, 0)
     62     # 把初始状态存入set集合
     63     expanded.add(status)
     64     # 队列不为空
     65     while qHead != qTail:
     66         status = myQueue[qHead].status
     67         if status == goal_status:  # 找到目标状态
     68             return True
     69         for i in range(4):  # 尝试4种移动方向
     70             # 根据moves[i]列表的方向移动,产生一个新的数
     71             newStatus = NewStatus(status, moves[i])
     72             # 不可移,试下一个方向
     73             if newStatus == -1:
     74                 continue
     75             # 已扩展过,试下一个方向
     76             if newStatus in expanded:
     77                 continue
     78             # 把新方向的状态整数值加入到队列中
     79             expanded.add(newStatus)
     80             # 按广度优先遍历的思路理解的话,qHead应该理解为层
     81             # 也就是新加入的这个节点是从哪层的某个状态转变过来的
     82             myQueue[qTail] = Node(newStatus, qHead, moves[i])
     83             qTail += 1
     84 
     85         qHead += 1
     86 
     87     return False
     88 
     89 
     90 def main():
     91     global qHead, myQueue
     92     result = [0 for i in range(400000)]  # 要输出的移动方案
     93     start_status = int(input())
     94     if bfs(start_status):
     95         n = 0
     96         pos = qHead
     97         # pos = 0 说明已经回退到初始状态了
     98         while pos != 0:
     99             # 通过father找到成功的状态序列,输出相应步骤
    100             # 从后往前找
    101             # kk = myQueue[pos].status
    102             result[n] = myQueue[pos].move
    103             pos = myQueue[pos].father
    104             n += 1
    105         print("共需要移动%d步" % n)
    106         print("具体的移动步骤如下:")
    107         for i in range(n-1, -1, -1):
    108             print(result[i])
    109     else:
    110         print("不能转换到该状态!")
    111 
    112     return 0
    113 
    114 
    115 if __name__ == '__main__':
    116     main()
     
  • 相关阅读:
    linux常用命令
    chattr无法删除某个文件
    centos如何卸载软件
    linux命令行下的ftp 多文件下载和目录下载
    yum -y upgrade 和 yum -y update 区别
    Pureftpd
    centos rar安装
    linux系统数据盘挂载教程
    anyexec
    _variant_t
  • 原文地址:https://www.cnblogs.com/an-wl/p/13375589.html
Copyright © 2011-2022 走看看