减少RAM BFS算法需要

时间:2016-11-21 03:36:45

标签: java breadth-first-search heap-dump

我编写了一个2x2x2 rubiks立方体求解器,它使用广度优先搜索算法来求解用户输入的立方体位置。该程序确实解决了多维数据集。但是当我进入一个难以解决的问题时,我遇到了一个问题,这个问题会在搜索中发现,我的堆空间已经用完了。我的电脑只有4 GB的RAM,当我运行程序时,我给它3GB。我想知道我能做些什么来减少搜索所需的内存量。可能通过改变BFS的几个方面。

static private void solve(Cube c) {

    Set<Cube> cubesFound = new HashSet<Cube>();
    cubesFound.add(c);

    Stack<Cube> s = new Stack<Cube>();
    s.push(c);

    Set<Stack<Cube>> initialPaths = new HashSet<Stack<Cube>>();
    initialPaths.add(s);

    solve(initialPaths, cubesFound);
}

static private void solve(Set<Stack<Cube>> livePaths, Set<Cube> cubesFoundSoFar) {
    System.out.println("livePaths size:" + livePaths.size());
    int numDupes = 0;

    Set<Stack<Cube>> newLivePaths = new HashSet<Stack<Cube>>();

    for(Stack<Cube> currentPath : livePaths) {

        Set<Cube> nextStates = currentPath.peek().getNextStates();

        for (Cube next : nextStates) {
            if (currentPath.size() > 1 && next.isSolved()) {
                currentPath.push(next);
                System.out.println("Path length:" + currentPath.size());
                System.out.println("Path:" + currentPath);
                System.exit(0);

            } else if (!cubesFoundSoFar.contains(next)) {
                Stack<Cube> newCurrentPath = new Stack<Cube>();
                newCurrentPath.addAll(currentPath);
                newCurrentPath.push(next);
                newLivePaths.add(newCurrentPath);
                cubesFoundSoFar.add(next);
            } else {
                numDupes += 1;
            }
        }
    }
    String storeStates = "positions.txt";
    try {
        PrintWriter outputStream = new PrintWriter(storeStates);
        outputStream.println(cubesFoundSoFar);
        outputStream.println(storeStates);
        outputStream.close();

    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    System.out.println("Duplicates found " + numDupes + ".");
    solve(newLivePaths, cubesFoundSoFar);
}

这就是BFS但是我担心它不是所有需要的信息来理解发生了什么,所以这里是所有代码的文件链接。 https://github.com/HaginCodes/2x2-Cube-Solver/blob/master/src/com/haginonyango/pocketsolver/Cube.java

1 个答案:

答案 0 :(得分:3)

根据定义,“最佳第一次搜索”会保留整个搜索前沿的可能路径。

这可能是指数级的。使用3x3x3魔方,我觉得有12个?在每个点上可能的移动,因此要解决的10个移动序列可能需要12 ^ 10个组合,这超过十亿(10 ^ 9)。在这许多州,您将希望最小化状态的大小以最小化总存储。 (呃,你实际上打印所有的状态?“outputStream.println(cubesFoundSoFar);”是不是有大量的输出?)

对于2x2x2,每个点只有8个可能的移动。我不知道随机问题的解决方案长度。如果它仍然是10,那么你得到8 ^ 10,这仍然很大。

现在,许多移动序列导致相同的立方体配置。要识别这一点,您需要检查生成的移动是否不会重新生成已访问过的位置。你好像这样做(好!)并跟踪点击次数;我希望命中数非常高,因为许多路径应该导致相同的配置。

您未展示的内容是您如何评分每个移动序列以指导搜索。它接下来扩展到什么节点?这是最佳发挥作用的地方。如果你没有任何指导(例如,枚举的所有移动序列具有相同的值),你真的会在一个巨大的空间中漫步,因为所有移动序列都同样好。是什么指导您的求解器解决方案?你需要像节点上的优先级队列那样优先级由得分决定,而我在这里给出的代码中没有看到。

我不知道将得分作为移动序列的质量来测量得分是多么好的启发式,但是你可以从移动序列开始,到达那里所需的移动次数。然后尝试的下一个“最佳动作”是具有最短路径的那个。这可能会有很大帮助。

(一个可能有效的简单增强功能是计算脸部的颜色数量; 3种颜色提示[这是真的吗?]可能需要3-1 - > 2次移动以移除错误的颜色。然后得分可能是#moves + #facecolors-1,来估计解决方案的移动次数;显然你想要最短的移动顺序。这可能是所谓的“可接受的”hueristic得分。)

您还必须调整方案以检测重复的移动序列。当你找到一个已经遇到的状态时,该状态现在可能已经附加了它到达该状态所需的分数(移动计数)。当你受到打击时,你已经找到另一种方式来达到相同的状态......但新路径的分数可能小于,而不是状态记录。在这种情况下,您需要使用较小的新分数修改已发现重复状态的分数。这样,事实上可以发现得分为20的路径/状态得分为10,这意味着它会突然改善。