检查数独字段的很酷的算法?
有谁知道一个简单的算法来检查数独配置是否有效? 我想出的最简单的算法是(对于大小为 n 的板)伪代码,
for each row
for each number k in 1..n
if k is not in the row (using another for-loop)
return not-a-solution
..do the same for each column
但我很确定一定有更好的(在更优雅的意义上)解决方案。 效率其实并不重要。
Does anyone know a simple algorithm to check if a Sudoku-Configuration is valid? The simplest algorithm I came up with is (for a board of size n) in Pseudocode
for each row
for each number k in 1..n
if k is not in the row (using another for-loop)
return not-a-solution
..do the same for each column
But I'm quite sure there must be a better (in the sense of more elegant) solution. Efficiency is quite unimportant.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(25)
您可以通过以下两种类似的方式检查数独是否已解决:
一个简单的解决方案是迭代每个方格,并检查该数字在该数字占据的行、列块中是否唯一。
但还有更好的方法。
。这只需要检查每一行、每一列和每一块,而不是对每个数字都这样做。 一个简单的实现是使用数字 1 到 9 的位字段,并在迭代列、行和块时删除它们。 如果您尝试删除缺失的数字,或者完成后该字段不为空,则数独无法正确解决。
You can check if sudoku is solved, in these two similar ways:
A naive solution would be to iterate trough every square and check if the number is unique in the row, column block that number occupies.
But there is a better way.
This only requires to check every row, column and block, instead of doing that for every number. A simple implementation would be to have a bitfield of numbers 1 trough 9 and remove them when you iterate the columns, rows and blocks. If you try to remove a missing number or if the field isn't empty when you finish then sudoku isn't correctly solved.
这是 Swift 中的一个非常简洁的版本,仅使用 Int 数组来跟踪 9 个数字的组,并且仅迭代数独一次。
Here's a very concise version in Swift, that only uses an array of Ints to track the groups of 9 numbers, and only iterates over the sudoku once.
您可以进行的一个小优化是,您可以在 O(n) 时间内而不是 O(n^2) 时间内检查行、列或框中的重复项:当您迭代一组数字时,您可以将每个数字添加到一个哈希集。 根据语言的不同,您实际上可能能够使用真正的哈希集,即恒定时间查找和插入; 然后可以在同一步骤中通过查看插入是否成功来检查重复项。 这是代码中的一个小改进,但从 O(n^2) 到 O(n) 是一个重大的优化。
One minor optimization you can make is that you can check for duplicates in a row, column, or box in O(n) time rather than O(n^2): as you iterate through the set of numbers, you add each one to a hashset. Depending on the language, you may actually be able to use a true hashset, which is constant time lookup and insertion; then checking for duplicates can be done in the same step by seeing if the insertion was successful or not. It's a minor improvement in the code, but going from O(n^2) to O(n) is a significant optimization.
您需要检查数独的所有约束:
总共 6 次检查..使用暴力方法。
如果您知道棋盘的大小(即 3x3 或 9x9),则可以使用某种数学优化
编辑:总和约束的说明:首先检查总和(如果总和不满足则停止) 45)比检查重复项更快(也更简单)。 它提供了一种丢弃错误解决方案的简单方法。
You need to check for all the constraints of Sudoku :
that's 6 checks altogether.. using a brute force approach.
Some sort of mathematical optimization can be used if you know the size of the board (ie 3x3 or 9x9)
Edit: explanation for the sum constraint: Checking for the sum first (and stoping if the sum is not 45) is much faster (and simpler) than checking for duplicates. It provides an easy way of discarding a wrong solution.
Peter Norvig 有一篇关于解决数独谜题(使用 python)的精彩文章,
https://norvig.com/sudoku.html
也许这对于你想做的事情来说太多了,但无论如何它都是一本很棒的书
Peter Norvig has a great article on solving sudoku puzzles (with python),
https://norvig.com/sudoku.html
Maybe it's too much for what you want to do, but it's a great read anyway
检查每一行、每一列和方框,确保其中包含数字 1-9,并且没有重复。 这里的大多数答案已经讨论过这一点。
但如何有效地做到这一点呢? 循环
答案:使用像每个数字都会设置结果的一位的 。 如果所有 9 个数字都是唯一的,则最小的 9
位将被设置。
因此,“检查重复项”测试只是检查所有 9 位是否已设置,这与测试结果==511 相同。
您需要执行其中 27 项检查……每行、每列和每框一项。
Check each row, column and box such that it contains the numbers 1-9 each, with no duplicates. Most answers here already discuss this.
But how to do that efficiently? Answer: Use a loop like
Each number will set one bit of the result. If all 9 numbers are unique, the lowest 9
bits will be set.
So the "check for duplicates" test is just a check that all 9 bits are set, which is the same as testing result==511.
You need to do 27 of these checks.. one for each row, column, and box.
想一想:您不需要检查每个 3x3 方格中的数字吗?
我试图弄清楚是否可以在没有正确数独的情况下满足行和列条件
Just a thought: don't you need to also check the numbers in each 3x3 square?
I'm trying to figure out if it is possible to have the rows and columns conditions satisfied without having a correct sudoku
这是我用 Python 编写的解决方案,我很高兴看到它是迄今为止最短的解决方案:)
代码:
以及执行:
This is my solution in Python, I'm glad to see it's the shortest one yet :)
The code:
And the execution:
为每一行、每一列和正方形创建一个布尔值数组。 数组的索引表示放入该行、列或正方形的值。 换句话说,如果将 5 添加到第二行第一列,则将 rows[2][5] 设置为 true,同时将 columns[1][5] 和 squares[4][5] 设置为 true,以指示行、列和正方形现在具有
5
值。无论您的原始董事会如何表示,这都可以是一种简单且非常快速的方法来检查其完整性和正确性。 只需按照数字在板上出现的顺序获取数字,然后开始构建此数据结构即可。 当您将数字放入棋盘中时,确定给定行、列或方格中是否有任何值重复的操作将变成 O(1)。 (您还需要检查每个值是否是合法数字:如果他们给您一个空白或一个太大的数字,您就知道该板不完整。)当您到达板的末尾时,您就会知道所有值都是正确的,并且不需要更多检查。
有人还指出,你可以使用任何形式的 Set 来做到这一点。 以这种方式排列的数组只是一种特别轻量级且高性能的 Set 形式,非常适合小型、连续、固定的数字集。 如果您知道电路板的大小,您也可以选择进行位屏蔽,但考虑到效率对您来说并不是那么重要,这可能有点过于乏味。
Create an array of booleans for every row, column, and square. The array's index represents the value that got placed into that row, column, or square. In other words, if you add a 5 to the second row, first column, you would set rows[2][5] to true, along with columns[1][5] and squares[4][5], to indicate that the row, column, and square now have a
5
value.Regardless of how your original board is being represented, this can be a simple and very fast way to check it for completeness and correctness. Simply take the numbers in the order that they appear on the board, and begin building this data structure. As you place numbers in the board, it becomes a O(1) operation to determine whether any values are being duplicated in a given row, column, or square. (You'll also want to check that each value is a legitimate number: if they give you a blank or a too-high number, you know that the board is not complete.) When you get to the end of the board, you'll know that all the values are correct, and there is no more checking required.
Someone also pointed out that you can use any form of Set to do this. Arrays arranged in this manner are just a particularly lightweight and performant form of a Set that works well for a small, consecutive, fixed set of numbers. If you know the size of your board, you could also choose to do bit-masking, but that's probably a little overly tedious considering that efficiency isn't that big a deal to you.
创建单元格集合,其中每个集合包含 9 个单元格,并为垂直列、水平行和 3x3 正方形创建集合。
然后,对于每个单元格,只需识别它所属的集合并对其进行分析即可。
Create cell sets, where each set contains 9 cells, and create sets for vertical columns, horizontal rows, and 3x3 squares.
Then for each cell, simply identify the sets it's part of and analyze those.
您可以将集合(行、列、框)中的所有值提取到列表中,对其进行排序,然后与 '(1, 2, 3, 4, 5, 6, 7, 8, 9) 进行比较
You could extract all values in a set (row, column, box) into a list, sort it, then compare to '(1, 2, 3, 4, 5, 6, 7, 8, 9)
我在一个班级项目中做过一次。 我总共用了 27 组来代表每一行、每一列和每一个方框。 当我将数字添加到每组时,我会检查数字(数字的每次放置都会导致数字被添加到 3 组,一行,一列和一个框),以确保用户只输入数字 1- 9. 填充集合的唯一方法是用唯一的数字正确填充它。 如果 27 组都填满,谜题就解决了。 设置从用户界面到 27 个集合的映射有点乏味,但使其余逻辑的实现变得轻而易举。
I did this once for a class project. I used a total of 27 sets to represent each row, column and box. I'd check the numbers as I added them to each set (each placement of a number causes the number to be added to 3 sets, a row, a column, and a box) to make sure the user only entered the digits 1-9. The only way a set could get filled is if it was properly filled with unique digits. If all 27 sets got filled, the puzzle was solved. Setting up the mappings from the user interface to the 27 sets was a bit tedious, but made the rest of the logic a breeze to implement.
将是非常有趣的
检查这是否满足数独的规则 。 因为这将允许 O(n^2) 的算法,对正确的单元格进行求和和相乘。
看 n = 9,总和应为 45,乘积为 362880。
您可以执行以下操作:
It would be very interesting to check if:
this suffices the rules of a sudoku. Because that would allow for an algorithm of O(n^2), summing and multiplying the correct cells.
Looking at n = 9, the sums should be 45, the products 362880.
You would do something like:
前段时间,我编写了一个数独检查器,用于检查每行上的重复数字、每列上的重复数字以及每行上的重复数字。 每个盒子上都有重复的号码。 如果有人能用几行 Linq 代码提出一个,我会很高兴。
Some time ago, I wrote a sudoku checker that checks for duplicate number on each row, duplicate number on each column & duplicate number on each box. I would love it if someone could come up one with like a few lines of Linq code though.
如果行/列的乘法和与等于正确的数字 45/362880
if the sum and the multiplication of a row/col equals to the right number 45/362880
首先,您需要创建一个布尔值“正确”。 然后,如前所述,创建一个 for 循环。 循环的代码以及之后的所有内容(在java中)如上所述,其中field是一个具有相等边的二维数组,col是另一个具有相同尺寸的数组,l是一个一维数组:
我不知道确切的算法要检查 3x3 框,但您应该使用“
/*此处为数组名称*/[i].contains(1)&&/*此处为数组名称*/ 检查 field 和 col 中的所有行[i].contains(2)
”(一直持续到达到一行的长度)在另一个 for 循环中。First, you would need to make a boolean, "correct". Then, make a for loop, as previously stated. The code for the loop and everything afterwards (in java) is as stated, where field is a 2D array with equal sides, col is another one with the same dimensions, and l is a 1D one:
I don't know the exact algorithim to check the 3x3 boxes, but you should check all the rows in field and col with "
/*array name goes here*/[i].contains(1)&&/*array name goes here*/[i].contains(2)
" (continues until you reach the length of a row) inside another for loop.Python 中有一个很好读的方法:
每个 3x3 的正方形称为一个块,3x3 的网格中有 9 个块。 假设谜题作为列表的列表输入,每个内部列表都是一行。
Here's a nice readable approach in Python:
Each 3x3 square is referred to as a block, and there are 9 of them in a 3x3 grid. It is assumed as the puzzle is input as a list of list, with each inner list being a row.
假设 int sudoku[0..8,0..8] 是数独字段。
}
Let's say int sudoku[0..8,0..8] is the sudoku field.
}
假设您的棋盘是从 1 - n。
我们将创建一个验证数组,填充它,然后验证它。
我认为这会成功,尽管我确信我在那里犯了一些愚蠢的错误。 我什至可能完全错过了这趟船。
Let's assume that your board goes from 1 - n.
We'll create a verification array, fill it and then verify it.
I think that will do the trick, although i'm sure i made a couple of stupid mistakes in there. I might even have missed the boat entirely.
如果没有彻底检查,我的头脑中,这应该可以工作(需要一些调试),而只循环两次。 O(n^2) 而不是 O(3(n^2))
Without thoroughly checking, off the top of my head, this should work (with a bit of debugging) while only looping twice. O(n^2) instead of O(3(n^2))
以下是数学教授 JF Crook 的论文:解决数独谜题的纸笔算法
这篇论文发表于 2009 年 4 月,作为确定的数独解决方案得到了广泛的宣传(在 google 上查找“JFCrook Sudoku”)。
除了算法之外,还有算法有效的数学证明(教授承认他觉得数独不是很有趣,所以他在纸上扔了一些数学以使其更有趣)。
Here is paper by math professor J.F. Crook: A Pencil-and-Paper Algorithm for Solving Sudoku Puzzles
This paper was published in April 2009 and it got lots of publicity as definite Sudoku solution (check google for "J.F.Crook Sudoku" ).
Besides algorithm, there is also a mathematical proof that algorithm works (professor admitted that he does not find Sudoku very interesting, so he threw some math in paper to make it more fun).
我会编写一个接口,其中包含接收数独字段的函数,并在它是解决方案时返回 true/false。
然后将约束实现为每个约束的单个验证类。
要验证,只需迭代所有约束类,当所有约束类都通过时,数独是正确的。 为了加速,将最有可能失败的结果放在前面,并停止在指向无效字段的第一个结果中。
非常通用的模式。 ;-)
您当然可以增强它以提供哪个字段可能是错误的提示等等。
第一个约束,只需检查所有字段是否已填写。 (简单循环)
第二次检查每个块中是否有所有数字(嵌套循环)
第三次检查完整的行和列(与上面的过程几乎相同,但访问方案不同)
I'd write an interface that has functions that receive the sudoku field and returns true/false if it's a solution.
Then implement the constraints as single validation classes per constraint.
To verify just iterate through all constraint classes and when all pass the sudoku is correct. To speedup put the ones that most likely fail to the front and stop in the first result that points to invalid field.
Pretty generic pattern. ;-)
You can of course enhance this to provide hints which field is presumably wrong and so on.
First constraint, just check if all fields are filled out. (Simple loop)
Second check if all numbers are in each block (nested loops)
Third check for complete rows and columns (almost same procedure as above but different access scheme)
这是我在 C 的地方。每个方格只经过一次。
Here is mine in C. Only pass each square once.
这是我刚刚为此所做的:
Here is what I just did for this: