当前位置: 首页 > 知识库问答 >
问题:

数独回溯算法(Java)

夹谷苗宣
2023-03-14

我已经创建了一个数独解算器,它可以像人类一样解数独,通过检查与被检查方格对应的方格中的可能性确定值。

(来源:http://pastebin.com/KVrXUDBF)

但是,我想创建一个随机数独生成器(从空白网格),因此决定使用回溯算法。我理解回溯的概念,但对一件事感到困惑:

一旦我知道某个解决方案是不允许的,我如何知道要返回(和更改)哪个前一个节点?我应该简单地返回到前一个节点并循环浏览所有可能性吗?(然后如果这没有产生正确的答案,则返回到之前的值,等等。)这似乎是一种可行的方法,但效率也很低。这是实现回溯方法的正确方法吗?还是有更好的方法可以实现它?

提前感谢。

可以在此处找到有关回溯的更多信息:http://en.wikipedia.org/wiki/Backtracking

共有3个答案

彭胡媚
2023-03-14

对于回溯解决方案,第一步是定义状态。所以对于这个问题,我认为最简单的方法是(x,y,blank,num),其中x,y是当前状态的位置,blank是剩余的空白位置数,而num是要填充该位置的值(从0到9,0表示空白)。

并且返回类型应该是布尔值,这决定了移动是否有效(这意味着此移动是否有任何有效的解决方案)。

因此,状态转换是逐列、逐行的:x,y到x,(y 1)或x,y到(x 1),0。同样,空白将来自-

public boolean move(int x, int y, int blank, int num, int[][]sudoku){
    sudoku[x][y] = num;
    //checking condition and return if x,y is the last position, code omitted
    if(y == sudoku[x].length){
            x++;
            y = 0;
    }else{
            y++;
    }
    for(int i = 1; i < 10; i++){
            if(move(x,y,blank,i,sudoku){//Backtrack here
                    return true;
            }
    }
    if(blank > 0){
            if(move(x,y,blank - 1, 0, sudoku){//Backtrack here
                    return true;
            }
    }
    return false;


}

因此,当从当前状态返回错误时,它将回溯到最后一个状态,最后一个状态将继续检查下一个num,直到找到正确的解决方案(或返回false)。

左丘烨烁
2023-03-14

生成随机数独的一种简单方法是,生成一个随机完成的数独,即生成随机数独,无方块为空
2)从1的平方中删除数字)
3)解数独2)。如果有许多解决方案,则添加在2)处删除的数字
如果仍有许多解决方案,请重复3)

1) 示例源代码

public int[][] generateRandomCompleteSudoku() {
  int[][] sudoku = new int[10];
  for(int i = 1; i <= 9; i++) {
    sudoku[i] = new int[10];
    Arrays.fill(sudoku[i], 0);
  }
  generateRandomCompleteSudoku(sudoku, 1, 1);
  return sudoku;
}
private boolean generateRandomCompleteSudoku(int[][] sudoku, int x, int y) {
  if(x > 9) {
    x = 1;
    y++;
  }
  //sudoku of the argument is completing sudoku.
  //so return true
  if(y > 9) {
    return true;
  }
  // enumerate the possible numbers of the pos(x,y). 
  List<Integer> possibleNumbers = new ArrayList<Integer>();
  for(int i = 1; i <= 9; i++) {
    boolean possible = true;
    //check i is a possible number.
    //check there isn't i in the raw of y .
    for(int j = 1; j <= x - 1; j++) {
      if(sudoku[j][y] == i) {
        possible = false;
        break;
      }
    }
    //check there isn't i in the column of x(omitted).
    //check there isn't i in the group of x,y(omitted).
    if(possible) {
      possibleNumbers.add(i);
    }
  }
  //sudoku is wrong so return false.(There is no solution of sudoku)
  if(possibleNumbers.size() <= 0) {
    return false;
  }
  Collections.shuffle(possibleNumbers);// This gives sudoku randomness.
  for(Integer possibleNumber : possibleNumbers) {
    sudoku[x][y] = possibleNumber;
    // a sudoku is generated, so return true
    if(generateRandomCompleteSudoku(sudoku, x + 1, y)) {
       return true;
    }
  }
  // No sudoku is generated, so return false
  return false;
}
许奇
2023-03-14

数独难题可以归结为图着色问题,可以使用简单的回溯(如为节点(1-9)指定颜色)来解决,直到所有直接连接的节点没有相同的颜色为止。

从数独构造图形:-

如果两个栅格点位于同一行、同一列或同一正方形中,则它们之间有一条直边。

回溯:-

  1. 为节点指定一种颜色(1-9)
  2. 检查是否没有其他颜色相同的直接连接节点
  3. 如果颜色有效,请移动到下一个节点
  4. 否则更改颜色并重新检查
  5. 如果所有颜色耗尽,则返回到上一个节点
  6. 执行递归,直到所有节点都是彩色的

完成后,您可以开始从网格中随机删除数字,直到您认为如果删除更多数字,问题就无法解决为止。

 类似资料:
  • 主要内容:回溯算法的应用场景在图 1 中找到从 A 到 K 的行走路线,一些读者会想到用穷举算法(简称穷举法),即简单粗暴地将从 A 出发的所有路线罗列出来,然后逐一筛选,最终找到正确的路线。 图 1 找从A到K的行走路线 图 1 中,从 A 出发的路线有以下几条: A-B-C A-B-D A-E-F-G A-E-F-H A-E-J-I A-E-J-K 穷举法会一一筛选这些路线,最终找到 A-E-J-K 。 本节要讲的回溯算

  • 主要内容:回溯VS递归,回溯算法的实现过程回溯算法,又称为 “试探法”。解决问题时,每进行一步,都是抱着试试看的态度,如果发现当前选择并不是最好的,或者这么走下去肯定达不到目标,立刻做回退操作重新选择。这种走不通就回退再走的方法就是回溯算法。 例如,在解决列举集合 {1,2,3} 中所有子集的问题中,就可以使用回溯算法。从集合的开头元素开始,对每个元素都有两种选择:取还是舍。当确定了一个元素的取舍之后,再进行下一个元素,直到集合最后一个元

  • 问题内容: 我创建了一个Sudoku Backtracking解算器,并且效果很好,但是现在我想给出一个错误,如果该数独无法解决,因为它是无效的,例如如果给出了这个数独: http://img5.imageshack.us/img5/2241/sudokugq.jpg 如果无法解决,我该怎么办才能使我的解决方法出错?我总是以零结束或陷入循环。 问题答案: 当然,当您触及代码时,您刚刚尝试了平方中的

  • 我的问题是,当一个9不能正确添加时,该方法会中断。不知何故,我不知道如何让它回到前一点,并向上数,这将创建一个新的“路径”,所以我想如果我做对了,一切都应该很好。我仍然在使用递归:-/ 正如我所知,我认为Sudokurecrect()做了它应该做的事情。编辑:您可以忽略布尔测试。我知道我不使用它,我试着想一些东西,但显然我不知道如何使用它。 输出为 在那之后,不管检查哪个变体。所以问题是一样的。

  • 我对编码还是很陌生的,我正在尝试一些稍微困难的主题,例如修改数独递归回溯程序的解决方案。最初的解决方案是针对大小为3x3的数独,我希望我的解决方案可以与正常大小的数独(9x9)一起使用。3x3解决方案在这里找到。 我觉得我对算法非常了解:对于网格中的每个列表(包含该单元格的可能值),在每一步尝试每个数字,确保电路板仍然有效,移动到下一个列表,分配一个可能的数字直到其有效,等等。如果当前电路板不正确

  • 我试图使用回溯在JavaScript中创建一个数独求解器,我做了一些研究,看到了类似的问题,但我的方法不同;而且没用。 使用它,浏览器停止响应,然后询问是否停止脚本。 在控制台中,我得到: 有什么问题的线索吗?