Sudoku Solver强力算法

时间:2013-04-12 22:36:07

标签: java algorithm recursion sudoku brute-force

仍然在我的数独求解器上工作,我又遇到了一些麻烦。我已经得到了数独求解器,但每当我试图解决一个真正“硬”的数独板时,我的求解器告诉我没有可能的解决方案,因为堆栈溢出错误。是的,我知道这些电路板有一个解决方案。

我正在使用强力算法 - 我从方形一开始(如果您愿意,则从[0] [0]开始)并插入第一个合法值。然后我对下一个方块进行递归调用,依此类推。如果我的函数没有通过整个板,并发现没有可能的合法值,它会移动到前一个方块并尝试在那里增加值。如果失败,它会进一步向后移动。如果它在没有可能的解决方案的情况下结束,则退出。

我承认我的代码并不漂亮,而且可能非常不妥协,但请记住,我是一名努力做到最好的一年级学生。我不介意如何有效地实现我的代码:)

对于没有最终预定义数字的正方形,这里是求解器函数:

public void fillRemainderOfBoard(Square sender){

    try {

        while(true){
            if(currentPos > boardDimension){
                if(previous != null){
                    this.setNumrep(-1);
                    this.setCurrentPos(1);
                    previous.setCurrentPos(previous.getCurrentPos()+1);
                    previous.fillRemainderOfBoard(this);
                    return;
                } else if(sender == this){
                    this.setCurrentPos(1); 
                } else {
                    break;
                }
            }
            if((thisBox.hasNumber(currentPos)) || (thisRow.hasNumber(currentPos)) || (thisColumn.hasNumber(currentPos))){
                currentPos++;
            } else {
                this.setNumrep(currentPos);
                currentPos++;
                break;
            }
        }

        if(this != last){
            next.setNumrep(-1);
            next.fillRemainderOfBoard(this);
        } else {

            return;
        }
    } catch (StackOverflowError e){
        return;
    }
}

在我的代码中,numrep值是方块在电路板上表示的值。 currentPos变量是一个从1开始并递增的计数器,直到达到要表示的正方形的合法值。

对于具有预定义数字的方块,这里的功能相同:

public void fillRemainderOfBoard(Square sender){
    if((sender.equals(this) || sender.equals(previous)) && this != last){
        System.out.println(next);
        next.fillRemainderOfBoard(this);
    } else if (sender.equals(next) && this != first) {
        previous.fillRemainderOfBoard(this);
    } else {
        System.out.println("No possible solutions for this board.");
    }
}

现在,我的问题是,就像我说的那样,该功能可以很好地解决sudokus问题。容易的。棘手的sudokus,就像有许多预定义数字和只有一个解决方案的那些,只是让我的程序进入堆栈溢出并告诉我没有可能的解决方案。我认为这表明我在内存管理方面缺少一些东西,或者我在递归函数中调用的程序复制对象,但我不知道如何修复它们。

非常感谢任何帮助!随意选择我的代码;我还在学习(哦,不是我们总是吗?)。

__ _ __ _ __ _ __ _ __ _ ____ 修改 _ __ _ __ < EM> _ __ _ __ _ __ _

感谢Piotr提出了回溯的好主意,我已经重写了我的代码。但是,我仍然无法让它解决任何数独游戏。即使有一个空板,它也会到达39号方块,然后一直返回false。这是我目前的代码:

public boolean fillInnRemainingOfBoard(Square sender){
    if(this instanceof SquarePredef && next != null){
        return next.fillInnRemainingOfBoard(this);
    } else if (this instanceof SquarePredef && next == null){
        return true;
    }

    if(this instanceof SquareNoPredef){
        currentPos = 1;
        if(next != null){
            System.out.println(this.index);
            for(; currentPos <= boardDimension; currentPos++){
                if((thisBox.hasNumber(currentPos)) || (thisRow.hasNumber(currentPos)) || (thisColumn.hasNumber(currentPos))){
                    continue;
                } else {
                    System.out.println("Box has " + currentPos + "? " + thisBox.hasNumber(currentPos));
                    this.setNumrep(currentPos);
                    System.out.println("Got here, square " + index + " i: " + numrep);
                }

                if(next != null && next.fillInnRemainingOfBoard(this)){
                    System.out.println("Returnerer true");
                    return true;
                } else {

                }
            }
        }
        if(next == null){
            return true;
        }
    }
    System.out.println("Returning false. Square: " + index + " currentPos: " + currentPos);
    return false;
}

我不得不复杂一点,因为我需要检查当前对象是否是最后一个。因此额外的if测试。哦,我使用boardDimension的原因是因为这个数独求解器将解决任何数独 - 而不仅仅是那些9乘以10的sudokus:)

你能发现我的错误吗?任何帮助表示赞赏!

1 个答案:

答案 0 :(得分:1)

所以你的问题就在这里:

previous.fillRemainderOfBoard(this);

在这里

next.fillRemainderOfBoard(this);

基本上你在堆栈上有太多的函数调用,因为你多次前进和后退。在找到答案之前你没有真正从任何调用返回(或者你得到StackOverflowError :))。而不是通过使用递归函数增加堆栈大小尝试思考如何使用循环解决问题(几乎总是循环优于递归解决方案性能明智)。 好的,你可以这样做(伪代码):

boolean fillRemainderOfBoard(Square sender){
 if (num_defined_on_start) {
     return next.fillRemainderOfBoard(this);
 } else {
   for (i = 1; i < 9; ++i) {
     if (setting i a legal_move)
        this.setCurrentPos(i);
     else
        continue;
     if (next.fillRemainderOfBoard(this))
       return true;
   }
   return false;
}

堆栈大小约为81。