创建数独谜题时出现重复问题

发布于 2024-08-08 01:05:00 字数 1019 浏览 3 评论 0原文

我正在尝试创建自己的普通 9x9 数独谜题

我将问题分为两部分 -

  1. 创建一个完全填充的数独,并
  2. 从中删除不必要的数字 网格

现在,我被第一部分困住了。


这是我简要使用的算法:

a)首先,我选择一个数字(例如 1),生成一个随机单元格位置,如果

  • 该单元格尚未被占用,并且
  • 该行还没有 现在我检查在一行、
  • b )
  • 一列或一个框中只有一个地方是空的

情况我填写

c) 我检查是否有一个数字不存在于某个框中,但存在于同一行和同一列的框中(我在这里谈论的是 3x3 框),则该数字的位置是固定的我填满它。

d) 重复上述步骤,直到每个数字在网格上出现九次。


我面临的问题是,我经常遇到这样的中间情况:

 0  1  0 | 0  0  3 | 0[4/2]0 
 0 [2] 0 | 0 [4] 1 | 3  0  0 
 3  0 [4]|[2] 0  0 | 0  0  1 
---------+---------+---------
 2  0  3 | 0  5  4 | 0  1  0 
 0  0  1 | 3  0  2 |[4] 0  0 
 0  4  0 | 0  1  0 |[2] 3  0 
---------+---------+---------
 1  0  2 | 0  3  0 | 0  0 [4] 
 4  3  0 | 1  0  0 | 0  0 [2] 
 5  0  0 | 4  2  0 | 1  0  3

看到写有[4/2]的地方吗?这是 2 和 4 的位置,因为框标记为 []。

我该怎么做才能避免陷入这种情况(因为这种情况是僵局 - 我无法进一步前进)

I am trying to create my own normal 9x9 sudoku puzzle.

I divided the problem into two parts -

  1. creating a fully filled sudoku, and
  2. removing unnecessary numbers from
    the grid

Right now, I am stuck with the first part.


This is the algorithm I use in brief:

a) first of all I choose a number (say 1), generate a random cell position, and place it there if

  • the cell is not already occupied, and
  • if the row does not already have the number, and
  • if the column does not already have the number, and
  • if the 3x3 box does not already have the number

b) now I check for a situation in which in a row, or a column or a box, only one place is empty and I fill that

c) I check that if there is a number that in not present in a box but is present in the boxes in the same row and the same column (i am talking about 3x3 boxes here), the number's place is fixed and I fill it.

d) I repeat the above steps until every number appears nine times on the grid.


The problem I am facing is that, more than often I am getting an intermediate situation like this:

 0  1  0 | 0  0  3 | 0[4/2]0 
 0 [2] 0 | 0 [4] 1 | 3  0  0 
 3  0 [4]|[2] 0  0 | 0  0  1 
---------+---------+---------
 2  0  3 | 0  5  4 | 0  1  0 
 0  0  1 | 3  0  2 |[4] 0  0 
 0  4  0 | 0  1  0 |[2] 3  0 
---------+---------+---------
 1  0  2 | 0  3  0 | 0  0 [4] 
 4  3  0 | 1  0  0 | 0  0 [2] 
 5  0  0 | 4  2  0 | 1  0  3

See the place with [4/2] written? that is the place of 2 as well as 4 because of the boxes marked [].

What can I do to avoid getting in this situation (because this situation is a deadlock - I cannot move further)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无风消散 2024-08-15 01:05:00

还有另一种生成数独谜题的方法:从一个已知的良好网格开始 - 任何一个都可以 - 然后通过应用不破坏不变量的操作来随机“洗牌”它。有效操作包括:

  • 交换块内的行
  • 交换块内的列
  • 交换块的整行(例如,前 3 行、中间 3 行、最后 3 行)
  • 交换块的整列 将
  • 一个数字的所有实例与另一个数字交换
  • 反映棋盘
  • 旋转棋盘board

通过这些操作,您可以生成非常大范围的可能的板。然而,您需要小心如何应用操作 - 就像简单的洗牌一样,很容易编写一种算法来使某些棋盘比其他棋盘更有可能出现。类似于 Knuth shuffle 的技术可能会有所帮助。

编辑:评论中指出,仅这些操作不足以创建每个可能的网格。

There's another way to generate sudoku puzzles: Start with a known good grid - any one will do - then randomly 'shuffle' it by applying operations that don't destroy the invariants. Valid operations include:

  • Swapping rows within a block
  • Swapping columns within a block
  • Swapping entire rows of blocks (eg, first 3, middle 3, last 3 rows)
  • Swapping entire columns of blocks
  • Swapping all instances of one number with another
  • Reflecting the board
  • Rotating the board

With these operations, you can generate a very large range of possible boards. You need to be careful about how you apply the operations, however - much like the naive shuffle, it's easy to write an algorithm that makes some boards more likely than others. A technique similar to the Knuth shuffle may help here.

Edit: It has been pointed out in the comments that these operations alone aren't sufficient to create every possible grid.

魂ガ小子 2024-08-15 01:05:00

你总会遇到这种情况。您需要递归回溯搜索来解决它。

基本上,确定特定数字对于单元格是否确实有效的唯一方法是继续搜索并查看会发生什么。

回溯搜索通常使用递归调用来完成。每次调用都将迭代一个单元格的(可能)仍然有效的选项,递归地评估下一个单元格的所有选项。当您无法继续时,回溯意味着从当前呼叫返回 - 当然,首先删除您为该单元格测试的任何数字。

当您找到有效的解决方案时,要么保存它并回溯以继续(即找到替代方案),要么中断所有递归调用以完成。递归回溯搜索的成功是一种特殊情况,在我看来,成功抛出异常是一个好主意 - 对于特定的调用成功来说是例外,并且代码会更清晰。

如果生成随机板,请按随机顺序迭代特定递归调用(对于特定单元格)中的选项。

相同的基本算法也适用于部分完成的棋盘(即解决现有数独) - 当评估已经有数字的单元格时,这是该单元格的唯一选择,因此递归到下一个单元格。

这是我曾经编写过的求解器的回溯搜索 - 很多内容都被抽象出来,但希望这能让原理更清晰......

size_t Board::Rec_Search (size_t p_Pos)
{
  size_t l_Count = 0;

  if (p_Pos == 81)  //  Found a solution
  {
    l_Count++;

    std::cout << "------------------------" << std::endl;
    Draw ();
    std::cout << "------------------------" << std::endl;
  }
  else
  {
    if (m_Board [p_Pos] == 0)  //  Need to search here
    {
      size_t l_Valid_Set = Valid_Set (p_Pos);

      if (l_Valid_Set != 0)  //  Can only continue if there are possible digits
      {
        size_t  l_Bit = 1;  //  Scan position for valid set

        for (size_t i = 1; i <= 9; i++)
        {
          if (l_Valid_Set & l_Bit)
          {
            Set_Digit  (p_Pos, i);
            l_Count += Rec_Search (p_Pos + 1);
          }

          l_Bit <<= 1;
        }

        Clr_Digit (p_Pos);  //  Ensure cleared properly for backtracking
      }
    }
    else  //  Already filled in - skip
    {
      l_Count += Rec_Search (p_Pos + 1);
    }
  }

  return l_Count;
}

You will always get that situation. You need a recursive backtracking search to solve it.

Basically, the only way to determine whether a particular digit really is valid for a cell is to continue the search and see what happens.

Backtracking searches are normally done using recursive calls. Each call will iterate through the (possibly) still valid options for one cell, recursing to evaluate all the options for the next cell. When you can't continue, backtracking means returning from the current call - erasing any digit you tested out for that cell first, of course.

When you find a valid solution, either save it and backtrack to continue (ie find alternatives), or break out of all the recursive calls to finish. Success in a recursive backtracking search is a special case where throwing an exception for success is IMO a good idea - it is exceptional for a particular call to succeed, and the code will be clearer.

If generating a random board, iterate the options in a particular recursive call (for a particular cell) in random order.

The same basic algorithm also applies for a partly completed board (ie to solve existing sodoku) - when evaluating a cell that already has a digit, well, that's the only option for that cell so recurse for the next cell.

Here's the backtracking search from a solver I wrote once - a lot is abstracted out, but hopefully that just makes the principle clearer...

size_t Board::Rec_Search (size_t p_Pos)
{
  size_t l_Count = 0;

  if (p_Pos == 81)  //  Found a solution
  {
    l_Count++;

    std::cout << "------------------------" << std::endl;
    Draw ();
    std::cout << "------------------------" << std::endl;
  }
  else
  {
    if (m_Board [p_Pos] == 0)  //  Need to search here
    {
      size_t l_Valid_Set = Valid_Set (p_Pos);

      if (l_Valid_Set != 0)  //  Can only continue if there are possible digits
      {
        size_t  l_Bit = 1;  //  Scan position for valid set

        for (size_t i = 1; i <= 9; i++)
        {
          if (l_Valid_Set & l_Bit)
          {
            Set_Digit  (p_Pos, i);
            l_Count += Rec_Search (p_Pos + 1);
          }

          l_Bit <<= 1;
        }

        Clr_Digit (p_Pos);  //  Ensure cleared properly for backtracking
      }
    }
    else  //  Already filled in - skip
    {
      l_Count += Rec_Search (p_Pos + 1);
    }
  }

  return l_Count;
}
爱人如己 2024-08-15 01:05:00

如果你已经达到了一个矛盾的状态,其中一个单元格同时是 2 和 4,那么你的其他一些 2 和 4 一定放置错误。您需要回滚并尝试一些不同的解决方案。

听起来您可能遇到算法问题? 这里有一些好东西。

If you've reached a contradictory state where a cell if both 2 and 4 some of your other 2s and 4s must be placed wrongly. You need to rollback and try some different solutions.

Sounds like you might have an algorithm problem? Some good stuff here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文