【问题标题】:Two Dimensional Array Constraints: Sudoku二维数组约束:数独
【发布时间】:2011-12-04 03:33:59
【问题描述】:

我正在尝试将数独作为家庭作业的约束满足问题来解决。我已经为特定行中的所有元素以及列构建了约束。我正在尝试为子区域中不同的元素构建约束,但遇到了一些麻烦。

我当前算法背后的总体思路是将子区域中的所有变量(例如 9x9 网格的 3x3 框)添加到列表中,然后排列该列表中的所有值以构造 NotEqualConstraints每个变量之间。下面的代码适用于 NxN 网格的第一个子区域,但我不确定应该如何更改它以遍历整个网格的其余部分。

int incSize = (int)Math.sqrt(svars.length);

ArrayList<Variable> subBox = new ArrayList<Variable>();

for (int ind = 0; ind < incSize; ind++) {
for (int ind2 = 0; ind2 < incSize; ind2++) {
    subBox.add(svars[ind][ind2]);
    }
}

for (int i = 0; i < subBox.size(); i++) {
for (int j = i + 1; j < subBox.size(); j++) {
   NotEqualConstraint row = new NotEqualConstraint(subBox.get(i), subBox.get(j));
   constraints.add(row);
   }
}

任何人都可以指导我如何修改代码以命中每个子区域,而不仅仅是左上角吗?

编辑:我也愿意尝试任何有效的算法,没有必要将所有值添加到每个子区域的 ArrayList 中。如果您看到更好的方法,请分享见解

【问题讨论】:

  • 啊,小伙子,你有什么问题?
  • 给定的代码迭代从网格左上角开始的第一个子区域,但不是网格的每个子区域。
  • 只是简单的算术,仅此而已。如果你在纸上算出来,你会立即看到算法。
  • 我已经在纸上解决了一段时间,对我来说不是那么容易:/

标签: java constraints constraint-programming


【解决方案1】:

以下是我想出的可行解决方案,供感兴趣的人参考:

for (int ofs = 0; ofs < svars.length; ofs++) {
    int col = (ofs % incSize) * incSize;
    int row = ((int)(ofs / incSize)) * incSize;

    ArrayList<Variable> subBox = new ArrayList<Variable>();
    for (int ind = row; ind < row+incSize; ind++) {
        for (int ind2 = col; ind2 < col+incSize; ind2++) {
            subBox.add(svars[ind][ind2]);
        }
    }
    for (int i = 0; i < subBox.size(); i++) {
            for (int j = i + 1; j < subBox.size(); j++) {
               NotEqualConstraint c = new NotEqualConstraint(subBox.get(i), subBox.get(j));
               constraints.add(c);
            }
    }   
}

【讨论】:

    【解决方案2】:

    我不完全确定您要做什么,但下面的算法应该会为您提供所需的每个值。您可以忽略和/或删除不需要的值。您可能可以在拥有所有数字的位置适当地填充所有数组。

    我用的词:

    • 方格:用于输入数字的单个方格。
    • 子区域:一组正方形,经典数独中的 3x3 网格。
    • 拼图:整个东西,3x3 子区域和 9x9 方块。

    代码:

    //You should have these values at this point:
    int subRegionWidth = something; //amount of horizontal squares in a subregion
    int subRegionHeight = something; //amount of vertical squares in a subregion
    int amountOfHorizontalSubRegions = something; //amount of subRegion columns next to each other
    int amountOfVerticalSubRegions = something; //amount of subregion rows on top of each other
    
    //Doesn't change, so calculated once in advance:
    int squaresPerPuzzleRow = subRegionWidth*amountOfHorizontalSubRegions;
    
    //Variables to use inside the loop:
    int subRegionIndex = 0;
    int squareColumnInPuzzle;
    int squareRowInPuzzle;
    int squareIndexInPuzzle;
    int squareIndexInSubRegion;
    
    for(int subRegionRow=0; subRegionRow<amountOfVerticalSubRegions;subRegionRow++)
    {
        for(int subRegionColumn=0; subRegionColumn<amountOfHorizontalSubRegions;subRegionColumn++)
        {
            for(int squareRowInRegion=0; squareRowInRegion<subRegionHeight; squareRowInRegion++)
            {
                for(int squareColumnInRegion=0; squareColumnInRegion<subRegionWidth; squareColumnInRegion++)
                {
                    squareColumnInPuzzle = subRegionColumn*subRegionWidth + squareColumnInRegion;
                    squareRowInPuzzle = subRegionRow*subRegionHeight + squareRowInRegion;
                    squareIndexInPuzzle = squareRowInPuzzle*squaresPerPuzzleRow + squareColumnInPuzzle;
                    squareIndexInSubRegion = squareRowInRegion*subRegionWidth + squareColumnInRegion;
    
                    //You now have all the information of a square:
    
                    //The subregion's row (subRegionRow)
                    //The subregion's column (subRegionColumn)
                    //The subregion's index (subRegionIndex)
                    //The square's row within the puzzle (squareRowInPuzzle)
                    //The square's column within the puzzle (squareColumnInPuzzle)
                    //The square's index within the puzzle (squareIndexInPuzzle)
                    //The square's row within the subregion (squareRowInSubRegion)
                    //The square's column within the subregion (squareColumnInSubRegion)
                    //The square's index within the subregion (squareIndexInSubRegion)
    
                    //You'll get this once for all squares, add the code to do something with it here.
                }
            }
            subRegionIndex++;
        }
    }
    

    如果您只需要每个子区域的左上角方块,只需删除内部的两个循环:

    for(int subRegionRow=0; subRegionRow<amountOfVerticalSubRegions;subRegionRow++)
    {
        for(int subRegionColumn=0; subRegionColumn<amountOfHorizontalSubRegions;subRegionColumn++)
        {
            squareColumnInPuzzle = subRegionColumn*subRegionWidth;
            squareRowInPuzzle = subRegionRow*subRegionHeight;
            squareIndexInPuzzle = squareRowInPuzzle*squaresPerPuzzleRow + squareColumnInPuzzle;
    
            //You now have all the information of a top left square:
    
            //The subregion's row (subRegionRow)
            //The subregion's column (subRegionColumn)
            //The subregion's index (subRegionIndex)
            //The square's row within the puzzle (squareRowInPuzzle)
            //The square's column within the puzzle (squareColumnInPuzzle)
            //The square's index within the puzzle (squareIndexInPuzzle)
            //The square's row within the subregion (always 0)
            //The square's column within the subregion (always 0)
            //The square's index within the subregion (always 0)
    
            //You'll get this once for all squares, add the code to do something with it here.
    
            subRegionIndex++;
        }
    }
    

    【讨论】:

      【解决方案3】:
      for (int start1 = start1; start1 < svars.length/incSize; start1 ++) {
          for (int start2 = start2; start2 < svars.length/incSize; start2++) {//iterate through all subsets
              ArrayList<Variable> subBox = new ArrayList<Variable>();
      
              for (int ind = start1*incSize; ind < incSize; ind++) {
                  for (int ind2 = start2*incSize; ind2 < incSize; ind2++) {
                       subBox.add(svars[ind][ind2]);
                  }
              }
      
             for (int i = 0; i < subBox.size(); i++) {
              for (int j = i + 1; j < subBox.size(); j++) {
                 NotEqualConstraint row = new NotEqualConstraint(subBox.get(i), subBox.get(j));
                 constraints.add(row);
                 }
              }
          }
      }
      

      【讨论】:

      • 上面的代码sn-p编译不了。出于某种奇怪的原因,您将 start1 初始化为自身而从未初始化 start1。 start2 也是如此。
      • 感谢您的快速回复。但是,我不确定您的算法是否正确,因为我对其进行了测试,并且无法识别除第一个子区域之外的每个子区域何时具有重复数字。请注意,我确实将 start1 和 start2 更改为初始化为 0。
      【解决方案4】:

      我不完全理解您要做什么,但是如果您要解决难题,则只需要一个递归方法,该方法将输入数字直到填满所有网格并且难题有效。这就是我的解决方案对于 futoshiki 解谜者(类似于数独)

      【讨论】:

      • 我正在解决这个难题作为一个约束满足问题。一旦建立了约束(我坚持的步骤),我就有一个算法来解决这个难题,这比蛮力更有效。
      • 投反对票作为帖子明确表示为 CSP 问题。显而易见的解决方案是递归,因为 CSP 需要 27*9!大约 600 万个不同的约束...
      • 你是如何推断这个数字的? 9x9 的约束数应为 810,4x4 应为 56。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-03
      • 1970-01-01
      • 2020-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多