java - Iterative Deepening A Star (IDA*) 解决 Java 中的 n-puzzle(滑动拼图)

标签 java artificial-intelligence puzzle graph-algorithm heuristics

我已经实现了一个能够解决 n-puzzle problem 问题的程序与*。由于状态空间太大,我无法预编译它,我必须在运行时计算可能的状态。通过这种方式,A* 对于 3-puzzle 可以很好地工作,但对于 4-puzzle 可能会花费太长时间。使用线性冲突调整的曼哈顿距离,如果最优解需要大约 25 次移动仍然很快,大约 35 次需要 10 秒,40 次需要 180 秒。我还没有尝试更多。
我认为那是因为我必须保留所有访问过的状态,因为我使用的函数是可接受的但(我认为)不一致(我还尝试了 Hamming 和 Gaschnig 距离以及更多)。由于解决方案的空间是一个图,启发式也必须是一致的,否则算法可能会循环或不是最优的。这就是为什么我保留所有访问过的节点(它也写在“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://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 循环中做了一些奇怪的事情。

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

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

确实,查看 public PuzzleSolution resolve(State start, State goal) 中的 while 循环,您会发现 nextCostBound+=2;。这意味着,每次尝试时,尝试找到最多 2 步以上的解决方案。


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

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

启发式算法位于 server/search/heuristic 文件夹中。

关于java - Iterative Deepening A Star (IDA*) 解决 Java 中的 n-puzzle(滑动拼图),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12033252/

相关文章:

java - 在 Java 中运行构造函数代码之前字段是否已初始化?

artificial-intelligence - RTS AI : where to start?

java - 存储单词联想的数据结构

c++ - 我 =++i+++i;在 C++ 中

java - 实现 Iterable 与实现 Iterator

java - org.codehaus.mojo :jaxb2-maven-plugin:2. 3.1:xjc 上的 Maven 构建失败

algorithm - 修改后的最小硬币变化

prolog - "Squares"Prolog中的逻辑谜语解决方案

java - 外部同步LinkedHashmap

python - 如何解决python机器学习中不在索引中的列