隐式图的搜索(预习报告)

本文探讨如何利用A*算法解决经典的九宫格八数码问题,通过建立图的启发式搜索方法,寻找从初始布局到目标布局的最短移动步骤。实验要求使用Java编程语言,实现A*算法,同时分析了三种不同的估价函数,最终选择曼哈顿距离作为估价标准以提高效率。文章还涉及了哈希表在判重中的应用,以及如何通过康托展开优化哈希函数。
摘要由CSDN通过智能技术生成

实验内容

  • 对九宫重排问题,建立图的启发式搜索求解方法。
  • 用A*算法求救九宫重排问题。

实验要求

3x3九宫棋盘,放置数码为1~8的8个棋子,棋盘中留有一个空格,空格周围的棋子可以移动到空格中,从而改变棋盘的布局。根据给定初始布局和目标布局,移动棋子从初始布局到达目标布局,求解移动步骤并输出。请设计算法,使用合适的搜索策略,在较少的空间和时间代价下找到最短路径。

编程语言和开发环境

编程语言:java
开发环境JDK11

实验思路

1.A*算法

  • 原理
     1. 把起点加入 open list 。
     2. 重复如下过程:
        a. 遍历open list ,查找F值最小的节点,把它作为当前要处理的节点,然后移到close list中
        b. 对当前方格的 8 个相邻方格一一进行检查,如果它是不可抵达的或者它在close list中,忽略它。否则,做如下操作:
        □ 如果它不在open list中,把它加入open list,并且把当前方格设置为它的父亲
        □ 如果它已经在open list中,检查这条路径 ( 即经由当前方格到达它那里 ) 是否更近。如果更近,把它的父亲设置为当前方格,并重新计算它的G和F值。如果你的open list是按F值排序的话,改变后你可能需要重新排序。
        c. 遇到下面情况停止搜索:
        □ 把终点加入到了 open list 中,此时路径已经找到了,或者
        □ 查找终点失败,并且open list 是空的,此时没有路径。
      3. 从终点开始,每个方格沿着父节点移动直至起点,形成路径。

  • 伪代码
    function A*(start, goal)
    // The set of nodes already evaluated.
    closedSet := {}
    // The set of currently discovered nodes still to be evaluated. Initially, only the start node is known.
    openSet := {start}
    // For each node, which node it can most efficiently be reached from.
    // If a node can be reached from many nodes, cameFrom will eventually contain the most efficient previous step.
    cameFrom := the empty map
    // For each node, the cost of getting from the start node to that node.
    gScore := map with default value of Infinity
    // The cost of going from start to start is zero.
    gScore[start] := 0
    // For each node, the total cost of getting from the start node to the goal
    // by passing by that node. That value is partly known, partly heuristic.
    fScore := map with default value of Infinity
    // For the first node, that value is completely heuristic.
    fScore[start] := heuristic_cost_estimate(start, goal)
    while openSet is not empty
    current := the node in openSet having the lowest fScore[] value
    if current = goal
    return reconstruct_path(cameFrom, current)
    openSet.Remove(current)
    closedSet.Add(current)
    for each neighbor of current
    if neighbor in closedSet
    continue // Ignore the neighbor which is already evaluated.
    // The distance from start to a neighbor
    tentative_gScore := gScore[current] + dist_between(current, neighbor)
    if neighbor not in openSet // Discover a new node
    openSet.Add(neighbor)
    else if tentative_gScore >= gScore[neighbor]
    continue // This is not a better path.
    // This path is the best until now. Record it!
    cameFrom[neighbor] := current
    gScore[neighbor] := tentative_gScore
    fScore[neighbor] := gScore[neighbor] + heuristic_cost_estimate(neighbor, goal)

    return failure

function reconstruct_path(cameFrom, current)
total_path := [current]
while current in cameFrom.Keys:
current := cameFrom[current]
total_path.append(current)
return total_path

2.A*算法解决九宫格问题

  • 问题描述
    八数码问题作为一个经典的问题被大家所熟知,该问题是求解如何从开始的一个状态(布局)到达目标状态所需步数最少的问题。
  • 问题分析
    将每一个状态作为一个结点容易想到可以用广搜的方法解决,这种方法简单,但是就算是加入哈希判重也会搜索很多的无用结点。
    我们打算用A算法解决这个问题,既然确定了用A算法,那么我们首先应该确定估价函数h(x),估价函数的选取直接决定A*算法的效率,一般对于八数码问题有三种估价函数的选法:
    以不在位的数码的个数为估价函数
    以不在位的数码归位所需的最短距离和即曼哈顿距离为估价函数
    将逆序对数作为估价函数
    可以证明前两种都是乐观估计,最后一种不是,因此前两种都可以作为八数码问题的估价函数,但是你的估计值与真实值越近所需要搜索的状态越少,很明显第一种方法太乐观了(估价函数的选取直接决定算法的效率),因此我们采用第二种方法作为八数码问题的估价函数
    解决了估价函数的问题以后,第二个需要解决的问题就是判重,我们首先想到的是用集合set,这种方法最简单,但是很不幸这种方法耗时也是最多的,如果时间要求比较高的话,这种情况很容易超时。这里我们不用这种方法,判重问题自然而然想到的是哈希表,好了现在问题又来了,如何创建哈希表,也就是哈希函数怎么写,这个东西比较有技巧,还好对于这种问题有一种现成的方法解决,那就是康托展开 ,还有一个问题就是有些问题是无解的,这种情况我们不希望进行很大力气的搜索之后发现无解,最好是能提前预知,值得庆幸的是八数码无论怎么移动逆序的奇偶性不变,因此我们可以直接通过O(1)的时间判断开始和目标结点的逆序奇偶性是否相同就可以了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值