数独解算器坏了
本文关键字:坏了 | 更新日期: 2023-09-27 18:06:51
我想先创建一个数独解算器
- 计算可以放入正方形的可能值。
- 然后使用这些约束回溯
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sudoku_Solver
{
static class Program
{
private static int[,] grid = new int[,]{
{ 3, 0, 6, 5, 0, 8, 4, 0, 0 },
{ 5, 2, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 8, 7, 0, 0, 0, 0, 3, 1 },
{ 0, 0, 3, 0, 1, 0, 0, 8, 0 },
{ 9, 0, 0, 8, 6, 3, 0, 0, 5 },
{ 0, 5, 0, 0, 9, 0, 0, 6, 0 },
{ 1, 3, 0, 0, 0, 0, 2, 5, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 7, 4 },
{ 0, 0, 5, 2, 0, 6, 3, 0, 0 }
};
private static List<int>[,] constraints;
static void Main(string[] args)
{
GetConstraints();
SolveSudokuGrid();
PrintGrid();
Console.Read();
}
static bool SolveSudokuGrid()
{
int row = -1 , col = -1;
if (IsGameOver(ref row, ref col) == true)
return true;
//Get constraint
List<int> constraint = constraints[row, col];
for (int i = 0; i < constraint.Count; i++)
{
//Assume correct number by adding a constraint
grid[row, col] = constraint[i];
if (SolveSudokuGrid() == true)
return true;
//Cant solve. Backtrack
grid[row, col] = 0;
}
return false;
}
static void PrintGrid()
{
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
Console.Write(grid[row,col]);
Console.WriteLine();
}
}
static bool IsGameOver(ref int row, ref int col)
{
for(int r = 0; r < 9; r++)
{
for(int c = 0; c < 9; c++)
{
if (grid[r, c] == 0)
{
row = r;
col = c;
return false;
}
}
}
return true;
}
static void GetConstraints()
{
constraints = new List<int>[9, 9];
for(int row = 0; row < 9; row++)
{
for(int col = 0; col < 9; col++)
{
if(grid[row,col] == 0)
{
constraints[row, col] = ComputeConstraint(row, col);
continue;
}
constraints[row, col] = null;
}
}
}
static List<int> ComputeConstraint(int row, int col)
{
List<int> constraint = new List<int>();
for (int i = 1; i <= 9; i++)
if (HasConflicts(row, col, i) == false)
constraint.Add(i);
return constraint;
}
static bool usedInRow(int row, int num)
{
/*
* Scans through that "row" till a match is found.
* So "row" will be the same, but "col" will keep changing as we scan
*/
for (int col = 0; col < 9; col++)
{
if (grid[row,col] == num)
{
return true;
}
}
return false;
}
static bool usedInCol(int col, int num)
{
/*
* Scans through that "col" till a match is found.
* So "col" will be the same, but "row" will keep changing as we scan
*/
for (int row = 0; row < 9; row++)
{
if (grid[row,col] == num)
{
return true;
}
}
return false;
}
static bool usedInBox(int boxStartRow, int boxStartCol, int num)
{
/*
* Scans through the mini 3x3 box, looking for a duplicate number
*/
for (int row = boxStartRow; row < boxStartRow + 3; row++)
{
for (int col = boxStartCol; col < boxStartCol + 3; col++)
{
if (grid[row,col] == num)
return true;
}
}
return false;
}
static bool HasConflicts(int row, int col, int num)
{
bool isInRow, isInCol, isInBox, hasConflicts = false;
isInRow = usedInRow(row, num);
isInCol = usedInCol(col, num);
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
isInBox = usedInBox(startRow, startCol, num);
if (isInRow)
{
hasConflicts = true;
}
if (isInCol)
{
hasConflicts = true;
}
if (isInBox)
{
hasConflicts = true;
}
return hasConflicts;
}
}
}
当您想要假设一个数字是正确的时,必须重新检查是否有重复的数字。如果之前添加的数字存在于当前列、行或框中,则转到下一个约束
你会得到错误的答案,因为你在把数字放入表格之前没有重新检查。
所以你可以在把数字放入表格之前用你自己的方法修复它。
你在SolveSudokuGrid
方法中的for循环应该像
for (int i = 0; i < constraint.Count; i++)
{
//Assume correct number by adding a constraint
// But lets do a check if we already added in current column or row or box.
if (usedInRow(row, constraint[i])) continue;
if(usedInCol(col, constraint[i])) continue;
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
if (usedInBox(startRow, startCol, constraint[i])) continue;
grid[row, col] = constraint[i];
if (SolveSudokuGrid() == true)
return true;
//Cant solve. Backtrack
grid[row, col] = 0;
}
并不是说这不能解决你当前的数独,因为给定的表是不可能解决的。所以它会返回没有变化的表。您还可以通过使用SolveSudokuGrid
的最终结果来检查表是否可解:
static void Main(string[] args)
{
GetConstraints();
bool solvable = SolveSudokuGrid();
if(!solvable) Console.WriteLine("Cannot solve!");
else PrintGrid();
Console.Read();
}
然而,有时你可能会陷入无限循环,因为错误的表和算法的设计(如果你放重复的数字)。但是,如果表本身不包含重复的数字,则应该可以正常工作。
更新:为了加速算法而不是按顺序分配数字,你必须将数字分配给正确可能性较小的元素。
这将大大提高算法的速度。这也是解决数独的常用方法。
您的IsGameOver
方法将像
static bool IsGameOver(ref int row, ref int col)
{
for (int r = 0; r < 9; r++)
{
for (int c = 0; c < 9; c++)
{
if (grid[r, c] == 0)
{
// set the row and col.
row = r;
col = c;
// but Lets check for the element with least possibilities in constraints.
// and prefer it against current row and col
int min = constraints[r, c].Count;
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (constraints[i, j] != null && // if the constraint is available
constraints[i, j].Count < min && // if found less possibilities
grid[i, j] == 0) // if the element of the table is 0 (its not assigned yet)
{
// set the row and col with less possibilities
row = i;
col = j;
min = constraints[i, j].Count;
}
}
}
return false;
}
}
}
return true;
}