Java 减少RAM BFS算法所需的内存量

Java 减少RAM BFS算法所需的内存量,java,breadth-first-search,heap-dump,Java,Breadth First Search,Heap Dump,我编写了一个2x2x2 rubiks立方体解算器,它使用广度优先搜索算法来解算用户输入的立方体位置。这个程序确实解决了立方体问题。然而,当我进入一个很难解决的位置时,我遇到了一个问题,这将在搜索的深处找到,我耗尽了堆空间。我的电脑只有4GB的内存,当我运行这个程序时,我给它3GB的内存。我想知道我能做些什么来减少搜索所需的内存量。可能通过改变BFS的几个方面 static private void solve(Cube c) { Set<Cube> cubesFound =

我编写了一个2x2x2 rubiks立方体解算器,它使用广度优先搜索算法来解算用户输入的立方体位置。这个程序确实解决了立方体问题。然而,当我进入一个很难解决的位置时,我遇到了一个问题,这将在搜索的深处找到,我耗尽了堆空间。我的电脑只有4GB的内存,当我运行这个程序时,我给它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);
}
static private void solve(多维数据集c){
Set cubesFound=new HashSet();
添加(c);
堆栈s=新堆栈();
s、 推(c);
Set initialpath=new HashSet();
初始路径。添加;
求解(初始路径,立方体已找到);
}
静态私有void solve(设置livepath,设置cubesFoundSoFar){
System.out.println(“livepath大小:+livepath.size());
int numDupes=0;
Set newlivepath=newhashset();
用于(堆栈currentPath:LivePath){
Set nextStates=currentPath.peek().getNextStates();
对于(多维数据集下一个:下一个状态){
if(currentPath.size()>1&&next.isSolved()){
currentPath.push(下一步);
System.out.println(“路径长度:+currentPath.size());
System.out.println(“路径:+currentPath”);
系统出口(0);
}如果(!cubesFoundSoFar.contains(下一个))包含,则为else{
Stack newCurrentPath=新堆栈();
newCurrentPath.addAll(currentPath);
newCurrentPath.push(下一步);
添加(newCurrentPath);
CubesFoundsFar.add(下一步);
}否则{
numDupes+=1;
}
}
}
字符串storeStates=“positions.txt”;
试一试{
PrintWriter outputStream=新的PrintWriter(StoreState);
outputStream.println(立方英尺);
outputStream.println(storeStates);
outputStream.close();
}catch(filenotfounde异常){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
System.out.println(“找到重复项”+numDupes+”);
求解(NewLivePath、CubesFoundsFar);
}
这就是BFS,但我担心它并不是理解正在发生的事情所需要的所有信息,所以这里是所有代码的文件链接

根据定义,“最佳优先搜索”保留了空间中可能路径的整个搜索边界

这可能是指数级的。用3x3x3魔方,我想有12个?每个点都有可能移动,所以一个10步序列的求解可能需要12^10个组合,远远超过10亿(10^9)。对于这么多的状态,您需要最小化状态的大小以最小化总存储。(呃,你实际上打印了所有的州?“outputStream.println(cubesFoundSoFar);“这不是一个很大的输出量吗?)

使用2x2x2,您在每个点上只有8个可能的移动。我不知道随机问题的解的长度。如果它的长度仍然是10,你会得到8^10,这仍然是相当大的

现在,许多移动序列导致相同的多维数据集配置。要认识到这一点,您需要检查生成的移动是否不会重新生成已访问的位置。你似乎正在这样做(很好!)并跟踪点击次数;我希望命中率相当高,因为许多路径应该指向相同的配置

你没有展示的是你如何为每个动作序列打分来指导搜索。下一步将扩展哪个节点?这是最好的发挥作用的地方。如果您没有任何指导(例如,枚举的所有移动序列都具有相同的值),那么您确实会在一个巨大的空间中徘徊,因为所有移动序列都同样好。什么引导您的解算器找到解决方案?您需要像节点上的优先级队列这样的东西,优先级由分数决定,我在这里介绍的代码中没有看到这一点

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

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


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

2x2x2多维数据集的术语略有不同。共有8件,可分为8种布局!可能的顺序,每件作品有3个可能的方向(因为每件作品是一个有3种颜色的角落)。那会给我们8个!*3^7种可能的组合。最值得注意的是,整个立方体有6条可能面向我们的边,对于这6条面向我们的边,我们可以顺时针或逆时针旋转立方体,使顶部显示4种不同的颜色。这意味着有8个!*3^7/(6*4)潜在组合(360万)@Ira BaxterAlso我确实写下了这些职位,因为我希望有一个包含所有职位的文件,当用户