使用DFS优化解决8数码问题

我正在使用Java通过深度优先搜索(DFS)来解决8数码问题。

这是我想到的解决方案:

    public static boolean found = false;        public void solveDepthFirst(EightPuzzle currentState, int lastMove){            if(currentState.goal()){                System.out.println(currentState);                found = true;//找到解决方案时停止DFS(即使不是最优解)                return;            }            for(int i=0;i<numMoves;++i){                if(found) return;                EightPuzzle e = currentState.move(i);//0 = 上,1 = 下,2 = 左,3= 右                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时,算法运行正常。然而,我相信还有很多其他优化可以做。

任何建议都将不胜感激。


回答:

首先,你可以使用堆栈代替递归调用。将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;//找到解决方案时停止DFS(即使不是最优解)            return;        }        for (int i = 0; i < 4; ++i) {            if (found)                return;            EightPuzzle e = currentState.move(i);// 0 = 上,1 = 下,2 =                                                    // 左,                                                    // 3= 右            if (!e.equals(currentState) && i != currentState.getLastMove()                    && !visitedNodes.contains(e)) {                stack.push(e); // queue.add(e);            }            if (!visitedNodes.contains(currentState.toString())) {                visitedNodes.add(currentState);            }        }    }}

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

之后,你可以通过使用优先级队列进一步优化(但这将不再是真正的DFS)。可以使用的启发式方法是曼哈顿距离。这样,最先搜索的解决方案将是最接近目标的。这种方法更有效,但不是严格的DFS。

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

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注