迭代加深 A Star (IDA*) 在 Java 中解决 n-puzzle(滑动拼图)

2023-12-29

我已经实现了一个能够解决这个问题的程序n-拼图问题 http://en.wikipedia.org/wiki/Fifteen_puzzle与 A*。由于状态空间太大,我无法预编译它,我必须在运行时计算可能的状态。通过这种方式,A* 对于 3 谜题来说效果很好,但对于 4 谜题可能需要很长时间。使用线性冲突调整的曼哈顿距离,如果最优解需要大约 25 次移动仍然很快,大约 35 次需要 10 秒,40 次需要 180 秒。我还没有尝试更多。
我认为这是因为我必须保留所有访问过的状态,因为我使用的是可接受的函数,但(我认为)不一致(我也尝试过汉明和加施尼格距离等)。由于解的空间是图,启发式也必须一致,否则算法可能会循环或不是最优的。这就是为什么我保留所有访问过的节点(它也写在《AI:一种现代方法》一书中)。但无论如何,这个存储速度一点也不慢。减慢速度的是保持要访问的节点队列的有序性。
因此,我决定尝试 IDA*,正如我所见,它不需要此存储(但我仍然必须保留所有访问过的状态以避免循环)。对于需要 35 步或更少步数的解决方案来说速度更快,但对于 40 步步数来说则慢得多。
这是我的代码。难道我做错了什么?

public static State solveIDAStar(State initialState) {
    int limit = initialState.getManhattanDistance() + 2 * initialState.getLinearConflicts();
    State result = null;
    while(result == null) {
        visitedStates.add(initialState); // It's a global variable
        result = limitedSearch(initialState, limit);
        limit = newLimit;
        visitedStates.clear();
    }
    return result;
}

public static State limitedSearch(State current, int limit) {
    for(State s : current.findNext()) {
        if(s.equals(GOAL)) {
            s.setParent(current);
            return s;
        }
        if(!visitedStates.contains(s)) {
            s.setPathCost(current.getPathCost() + 1);
            s.setParent(current);
            int currentCost = s.getManhattanDistance() + 2 * s.getLinearConflicts() + s.getPathCost();
            if(currentCost <= limit) {
                visitedStates.add(s);
                State solution = limitedSearch(s, limit);
                if(solution != null)
                    return solution;
            } else {
                if(currentCost < newLimit)
                    newLimit = currentCost;
            }
        }
    }
    return null;
}

旧的东西搬下来了。

进行更改,以便 newLimit 可以跳过步骤(bestSolution 的东西):

State bestSolution; // add this global

public static State solveIDAStar(State initialState) {
    int limit = initialState.getManhattanDistance() + 2 * initialState.getLinearConflicts();
    bestSolution = null; // reset global to null
    State result = null;
    while(result == null) {
        visitedStates.add(initialState); // It's a global variable
        newLimit = INFINITY;
        result = limitedSearch(initialState, limit);
        limit = newLimit;
        visitedStates.clear();
    }
    return result;
}

public static State limitedSearch(State current, int limit) {
    for(State s : current.findNext()) {
        if(s.equals(GOAL)) {
            s.setParent(current);
            return s;
        }
        if(!visitedStates.contains(s)) {
            s.setPathCost(current.getPathCost() + 1);
            s.setParent(current);
            int currentCost = s.getManhattanDistance() + 2 * s.getLinearConflicts() + s.getPathCost();
            if(currentCost <= limit) {
                visitedStates.add(s);
                State solution = limitedSearch(s, limit);
                if(solution != null &&
                   (bestSolution == null || solution.getPathCost() < bestSolution.getPathCost()))
                        bestSolution = solution; // cache solution so far
            } else {
                if(currentCost < newLimit)
                    newLimit = currentCost;
            }
        }
    }
    return null;
}

原答案

所以我找到了一个开源实现。神奇的是,它也在java中。

该应用程序可以在这里进行测试:http://n-puzzle-solver.appspot.com/ http://n-puzzle-solver.appspot.com/

具体相关的源代码是:http://code.google.com/p/julien-labs/source/browse/trunk/SlidingPuzzle/src/be/dramaix/ai/slidingpuzzle/server/search/IDAStar.java http://code.google.com/p/julien-labs/source/browse/trunk/SlidingPuzzle/src/be/dramaix/ai/slidingpuzzle/server/search/IDAStar.java

不确定下面建议的第一个更改可能会改变多少时间,但我很确定您需要进行第二个更改。


第一次改变

通过对比代码,你会发现这个函数

private Node depthFirstSearch(Node current, int currentCostBound, State goal)

基本上是你在这里的功能

public static State limitedSearch(State current, int limit)

Julien Dramaix 的实现没有:

if(!visitedStates.contains(s)) {
    ...
    visitedStates.add(s);

所以把这两条线拿出来测试一下。


第二次改变

你的职能public static State solveIDAStar(State initialState)在 while 循环中做了一些奇怪的事情。

失败一次后,您将最大深度(限制)设置为无穷大。基本上,第一次迭代时,您尝试找到与您的启发式一样好的解决方案。然后你尝试寻找任何解决方案。这不是迭代深化.

迭代深化意味着每次尝试时,都要更深入一点。

事实上,看看 while 循环public PuzzleSolution resolve(State start, State goal), 你会找到nextCostBound+=2;。这意味着,每次尝试时,请尝试通过最多 2 个动作找到解决方案。


否则,其他一切看起来都很相似(尽管 State 类的确切实现可能略有不同)。

如果效果更好,您可能还想尝试其他一些启发式方法http://code.google.com/p/julien-labs/source/browse/#svn%2Ftrunk%2FSlidingPuzzle%2Fsrc%2Fbe%2Fdramaix%2Fai%2Fslidingpuzzle%2Fclient http://code.google.com/p/julien-labs/source/browse/#svn%2Ftrunk%2FSlidingPuzzle%2Fsrc%2Fbe%2Fdramaix%2Fai%2Fslidingpuzzle%2Fclient.

启发式方法可在 server/search/heuristic 文件夹中找到。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

迭代加深 A Star (IDA*) 在 Java 中解决 n-puzzle(滑动拼图) 的相关文章

随机推荐

  • 如何从 OSGi 运行时环境中通过类名字符串加载类?

    我正在制作一个捆绑包来插入 OSGi 来为用户提供一个功能 Usercase User input the classname string and click list button the corresponding class wil
  • request.GET.get 是什么意思?

    request GET get 是什么意思 我在 Django 中看到类似的东西 page request GET get page 1 我认为这与类似的事情有关 li a href laquo a li 它们是如何工作的 The requ
  • Neo4J 3.0中配置文件的位置在哪里?

    我最近安装了 Neo4j 3 0 由于我需要启用外部访问 因此我需要配置文件 以及 2 3 3 中配置文件位于 var lib neo4j 结构中的位置 我无法在 3 0 版本中的任何位置找到它们 我知道它已更名为 neo4j conf 我
  • 使用apache和passenger部署rails应用程序后,显示页面不存在

    我已经使用 apache2 和乘客部署了 Rails 应用程序 一切都很顺利 但部署后它说您正在寻找的页面不存在 我的应用程序名称是 opengrok 我的 apache 配置位于 etc apache2 sites avaibleable
  • 终止使用子进程打开的 gnome 终端

    使用子进程和命令 gnome terminal e bash 我可以根据需要打开一个 gnome 终端 并让它保留在周围 这是通过以下任一方法完成的 p subprocess Popen gnome terminal e bash or p
  • Android Marshmallow - 自定义搜索栏进度条未显示

    我正在尝试像这样自定义我的搜索栏 在 API 级别 My seek bar progress bar xml
  • Hibernate 向数据库发送外来查询

    我有一个由 hibernate 支持的 Web 应用程序 在过去的几天里 我开始密切监视 mysql 发现 hibernate 正在向数据库发送未知查询 而这些查询实际上不是从应用程序的任何部分发送的 查询看起来像 mysql connec
  • 如何在 Swift 中识别连续触摸?

    如何在 Swift 代码中识别连续的用户触摸 我所说的连续是指用户将手指放在屏幕上 只要用户触摸屏幕 我就想将精灵套件节点移动到用户触摸的方向 基本步骤 存储触摸事件的位置 touchesBegan touchesMoved 将精灵节点移向
  • 在 Windows XP 中设置 Tomcat 服务的默认区域设置

    我已在 Windows XP 计算机中安装了 Apache Tomcat 6 作为服务 法语 我的问题是 Tomcat 本身和所有网络应用程序 Sonar 和 Hudson 现在显示法语消息 我当然想要英文消息 所以我进入控制面板中的 区域
  • 如何将 @State 值分配给另一个 viewModel 发布的属性

    如何将一个视图中的 State 值 secondaryMarked 分配给 Published SampleViewModel 属性 喜欢 SampleViewModel secondMarked 这是示例 struct ContentVi
  • 编译 openCV 代码时出现“函数未在此范围内声明”错误

    我正在尝试编写一些使用 openCV 函数的代码 我首先采用文档中提供的一些示例代码 include
  • VBScript 中的 XPath 计数

    我尝试使用 XPath 计数函数获取 XML 文件中特定节点的数量 但是 这不断返回错误 msxml3 dll 类型的异常 表达式不返回 DOM 节点 如何使用 VBScript 和 MSXML DOM 从 XPath 计数获取返回值 Di
  • 以数组为原型的 Javascript 对象成员由所有类实例共享

    以前有人注意到这种行为吗 这真的让我很失望 我本来期望原型数组对于每个类实例都是私有的 而不是在所有类实例之间共享 有人可以验证这是正确的行为 并且也许可以更详细地解释这种行为吗 请注意注释的代码以及它如何影响脚本的行为
  • 有没有好的交互式 3D 图形库?

    我正在寻找一个库 它将以 3D 方式布局和显示图形 即网络图 而不是图表 并具有一些交互性 例如选择和拖动节点 旋转显示等 我想在网页中执行此操作 因此 Javascript或 Flash 更好 我也会考虑 Java 自我审视后 我意识到选
  • Action<>多参数语法说明

    有时我无法理解最简单的事情 我确信它就在我的脸上 只是我看不到它 我尝试为这个简单类中的方法创建委托 public static class BalloonTip public static BalloonType BalType get
  • Linux下Git克隆fsync输入/输出错误

    我正在尝试克隆张量流 模型存储库 我通过 ssh 连接到远程计算机 我尝试了很多解决问题的建议 但没有一个对我有用 git clone recursive https github com tensorflow models git Clo
  • Firebase 云消息传递是否需要服务器?

    我目前正在开发一个 Android 应用程序 我想包含 Firebase Cloud Messaging 我计划让 Raspberry Pi 每 5 分钟左右检查一次网站 并在发生变化时发送推送通知 在官方文档中 他们说我需要一个 应用程序
  • 检查 Pandas 数据框是否存在异常值[重复]

    这个问题在这里已经有答案了 传感器图 https i stack imgur com OahnS png 我对包含 8 个电极的传感器进行了实验 上图是电极输出与时间的关系图 正如您在图中看到的 8 个电极之一显然是异常值 可能是由于某些电
  • -ObjC 链接器标志有什么作用?

    我有一个可以使用和不使用链接器标志的应用程序 但是 如果没有链接器标志 向视图添加数据时我会得到非常不同的行为 该标志使链接器加载库中定义 Objective C 类或类别的每个目标文件 虽然此选项通常会导致更大的可执行文件 由于将额外的目
  • 迭代加深 A Star (IDA*) 在 Java 中解决 n-puzzle(滑动拼图)

    我已经实现了一个能够解决这个问题的程序n 拼图问题 http en wikipedia org wiki Fifteen puzzle与 A 由于状态空间太大 我无法预编译它 我必须在运行时计算可能的状态 通过这种方式 A 对于 3 谜题来