繁体   English   中英

计算给定数独难题的解决方案数量?

[英]Counting the number of solutions for a given sudoku puzzle?

我正在开发一个基于Web的数独游戏,允许用户自定义自己的数独板。 我需要一种方法来告诉用户他组装的电路板有多少可行的解决方案。 数独具有唯一解的最小条目数为17。我需要找到条目数小于17的解决方案数。

这是我的方法:

public long numberOfSolutions (Board myBoard) {
    this.board = myBoard;
    this.tempBoard = new Board();
    long num = 0;

    tempBoard.copy(board);
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            if (board.getCell(i,j).equals(0)) {
                for(int k=1;k<10;k++){
                    board.setCell(i, j, k, true);
                    if(isCorrect() && solvable()){
                        num++;
                    }
                    board.copy(tempBoard);
                }
            }
        }
    }
    return num;
}

因此,基本上,我为每个空单元格插入1-9之间的数字,并尝试为每个数字求解游戏。 如果成功,则增加解决方案的数量。 但这并不能为我提供所有可能组合的数量,而是可以插入的每个单元格的数量之和。

有办法计算吗?

答案是(可能):不要那样做。

Sudoku解决方案是NP完全的 ,因此解决一个问题可能需要一段时间,更不用说解决方案的数量了。

即使您尝试计算计数,它也可能非常大。 没有任何内容的数独板有6,670,903,752,021,072,936,960答案。

我不会讲太多Java,但这是递归方法的基本描述:

如果电路板有错误(即同一行,列或框中的两个相同数字),则解决方案为零。 如果没有错误并且电路板已满,则有一种解决方案。 如果没有错误,但板没有装满,请选择最早的空单元格,然后对该单元格中包含1、2,...,9的板的解决方案总数求和。

这不是最好的方法,但是可以完成工作,而且我敢肯定,一旦代码真正出现在屏幕上,就需要进行一些优化。

也许我几年前保存的东西可能会在下面给出一些想法,在这种情况下,如果给定条件允许,那么候选最多的单元而不是选择最少的单元似乎可以确保多个解决方案,然后停在计数等于2。 否则,尽可能地解决难题,只有在空单元格足够少的情况下,才可能进行计数。 因为它是html代码,所以我不确定您是否可以看到它,但是这里是:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <HTML>
    <HEAD>
    <TITLE>Sudoku Solver</TITLE>
    <META name="Keywords" content="Sudoku, Simple, javascript, puzzle">
    <META name="Description" content="Simple Sudoku Solver, written in JavaScript">
    <script type="text/javascript">
    function Board() {
     this.cells=new Array();
     for (var i=0; i<81; ++i)
      this.cells[i]=0;
    }

    function CopyBoard(dest, src) {
     for (var i=0; i<81; ++i)
      dest.cells[i]=src.cells[i];
    }
    function CountConstraints(val) {
     var cc=0;
     for (var i=1; i<=9; ++i)
      if (((1<<i) & val)!=0) ++cc;
     return cc;
    }
    function MostConstrained() {
     var max=-1, maxp=-1;
     for (var i=0; i<81; ++i) {
      if ((this.cells[i] & 1)==0) {
       v=CountConstraints(this.cells[i]);
       if (v>=max) {
        max=v;
        maxp=i;
       }
      }
     }
     return maxp;
    }

    Board.prototype.mostConstrained=MostConstrained;

    function AllOptions(val) {
     var cc=new Array;
     var n=0;
     for (var i=1; i<=9; ++i)
      if (((1<<i) & val)==0) cc[n++]=i;
     return cc;
    }

    function SetValue(pos, val) {
      var x=pos%9;
      var y=Math.floor(pos/9);
      var x0=Math.floor(x/3)*3;
      var y0=Math.floor(y/3)*3;
      var add=(1<<val);
      for (var k=0; k<9; ++k) {
        this.cells[x+k*9]|=add;
        this.cells[k+y*9]|=add;      
        this.cells[x0+(k%3)+9*(y0+Math.floor(k/3))]|=add;}
      this.cells[pos]=1023-(1<<val);
    }
    Board.prototype.setValue=SetValue;

    function CellText(d) {
     if (d&1) {
      for (var i=1; i<=9; ++i)
       if ((d | (1<<i))==1023) return ""+i;
      return "_";
     }
     else {
      return "?"+AllOptions(d);
     }
    }
    function AsHTML() {
     var ans="";
     for (var y=0; y<9; ++y) {
      ans=ans+"<tr>"
      for (var x=0; x<9; ++x) {
       ans=ans+"<td class=sol>"+CellText(this.cells[x+y*9])+"<\/td>";
      }
      ans=ans+"<\/tr>";
     }
     return "<table border=1>"+ans+"<\/table>"
    }
    Board.prototype.asHTML=AsHTML; 

    function IsOK() {
     for (var i=0; i<81; ++i) {
      if ((this.cells[i] & 1022)==1022) {
        return false;
      }
     }
     return true;
    }  

    function IsSolved() {
     for (var i=0; i<81; ++i) {
      if ((this.cells[i] & 1)==0) return false;
     }
     return true;
    }

    Board.prototype.isSolved=IsSolved;
    Board.prototype.isOK=IsOK;

    var theOne=new Board();
    var numSol;

    function SearchSolutions() {
        while (this.isOK()) {
            if (this.isSolved()) {
                if (1<++numSol) return this;
                CopyBoard(theOne,this);return null;}
            var p=this.mostConstrained();
            if (p<0) return null;
            var l=AllOptions(this.cells[p]);
            if (l.length<1) return null;
            for (var i=1; i<l.length; ++i) {
                var nb=new Board();
                CopyBoard(nb, this);
                nb.setValue(p, l[i]);
                nb=nb.searchSolutions();
                if (nb) return nb;}
            this.setValue(p, l[0]);}
        return null;
    }
    Board.prototype.searchSolutions=SearchSolutions;

    function DrawInput() {
     var ans="";
     for (var y=0; y<9; ++y) {
      ans=ans+"<tr>"
      for (var x=0; x<9; ++x) {
       ans=ans+"<td class=sol><input size=1 type=text id='C"+(x+y*9)+"'><\/td>";
      }
      ans=ans+"<\/tr>"
     }
     document.write("<table border=1>"+ans+"<\/table>");
    }
    function solve_click() {
        var theSec=new Board();
        numSol=0;
        for (var i=0; i<81; ++i) {
        var v=document.getElementById("C"+i).value
        if (v>="1" && v<="9") theSec.setValue(i, parseInt(v));}
        var rsp=theSec.searchSolutions();
        var ans="<p>No solution<\/p>";
        if (numSol==1) ans="<p>Valid Sudoku - One and only one solution !<\/p>"+theOne.asHTML();
        if (numSol==2) ans="<p>Invalid Sudoku - More than one solution !<\/p>"+theOne.asHTML()+"<p><\/p>"+rsp.asHTML();
        document.getElementById("answer").innerHTML=ans;
    }

    </SCRIPT>

    <STYLE type=text/css>
    .sol {
        WIDTH: 1em; HEIGHT: 1em
    }
    </STYLE>
    </HEAD>
    <BODY>
    <h1>Sudoku Solver</h1>
    <a href="solverabout.html"><span style="font-size: smaller">(about)</span></a>

    <div>
    <script type="text/javascript">
     DrawInput();
    </script>
    <input type="button" value="Solve" onclick="solve_click();">
    </div>
    <div id="answer"></div>
    </BODY>
    </HTML>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM