使用DFS优化解决8-Puzzle

时间:2012-02-09 01:26:53

标签: java artificial-intelligence stack-overflow depth-first-search

我正在使用Java来解决使用DFS的8-Puzzle问题。

这就是我提出的:

    public static boolean found = false;

        public void solveDepthFirst(EightPuzzle currentState, int lastMove){

            if(currentState.goal()){
                System.out.println(currentState);
                found = true;//to stop DFS when a solution is found (even if not optimal)
                return;
            }

            for(int i=0;i<numMoves;++i){
                if(found) return;

                EightPuzzle e = currentState.move(i);//0 = up, 1 = down, 2 = left, 3= right

                if(!e.equals(currentState) && i != lastMove
                        && !visitedNodes.contains(e.toString())){
                    solveDepthFirst(e, i);  
                }           
                     if(!visitedNodes.contains(currentState.toString())){
                visitedNodes.add(currentState.toString());
                     }
            }
        }

!e.equals(currentState)检查是否可以移动。 (如果currentState.move(i)超出范围,则move()返回相同的状态)

i!= lastMove确保如果在你的最后一步中你向前移动,你现在不要向左移动(因为它没有感觉到)

visitedNodes 是受访节点的HashSet。

这是堆栈空间不足。当我使用-xss10m将堆栈空间从128k增加到10m时,算法运行正常。但是我确信可以进行大量其他优化。

任何提示都将不胜感激。

2 个答案:

答案 0 :(得分:1)

我认为通过在继续进行递归调用之前标记所访问的状态,可以大大加快搜索速度。除此之外,对这个难题没有太多的优化:你只需要尝试所有可能的动作。

答案 1 :(得分:1)

首先,您可以进行堆栈而不是递归调用。 将lastMove添加到EightPuzzle类。

这就是你得到的:

// Queue<EightPuzzle> queue = new PriorityQueue<EightPuzzle>();
Stack<EightPuzzle> stack = new Stack<EightPuzzle>();

public void solveDepthFirst() {

    while (true) {
        EightPuzzle currentState = stack.pop(); // queue.poll();
        if (currentState.goal()) {
            System.out.println(currentState);
            found = true;// to stop DFS when a solution is found (even if
                            // not
                            // optimal)
            return;
        }

        for (int i = 0; i < 4; ++i) {
            if (found)
                return;

            EightPuzzle e = currentState.move(i);// 0 = up, 1 = down, 2 =
                                                    // left,
                                                    // 3= right

            if (!e.equals(currentState) && i != currentState.getLastMove()
                    && !visitedNodes.contains(e)) {
                stack.push(e); // queue.add(e);
            }
            if (!visitedNodes.contains(currentState.toString())) {
                visitedNodes.add(currentState);
            }
        }
    }
}

使用递归调用而不是迭代设计时,性能会显着下降。

之后,您可以使用PriorityQueue进一步优化(但不会是真正的DFS)。使用的启发式可以是曼哈顿距离。这样,要搜索第一个的解决方案是最接近目标的。它更有效但不严格DFS。

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/PriorityQueue.html