如何在C中填充空的数独板
我接到一个任务,写一个程序,填充一块空的数独板并打印出来 我们拥有的工具只有函数、数组和指针。没有递归,没有搜索和排序算法来提高时间复杂度 到目前为止,我想对电路板使用二维数组,并在嵌套的“for”循环中遍历每一行 每次我用随机函数取一个数字,检查一行、一列和一个正方形(3X3),如果它们都通过了,我就填充这个数字 我的问题是,这样代码需要很长时间才能解决,我不知道我是否做对了。我还没有看到我的代码的解决方案,即使让它运行5分钟以上。我想也许可以用一个1-9的数字直方图来映射那些已经用来改变随机数提取方法的数字,但我真的不确定如何使用它,以及这样做是否正确。基本上我被卡住了如何在C中填充空的数独板,c,C,我接到一个任务,写一个程序,填充一块空的数独板并打印出来 我们拥有的工具只有函数、数组和指针。没有递归,没有搜索和排序算法来提高时间复杂度 到目前为止,我想对电路板使用二维数组,并在嵌套的“for”循环中遍历每一行 每次我用随机函数取一个数字,检查一行、一列和一个正方形(3X3),如果它们都通过了,我就填充这个数字 我的问题是,这样代码需要很长时间才能解决,我不知道我是否做对了。我还没有看到我的代码的解决方案,即使让它运行5分钟以上。我想也许可以用一个1-9的数字直方图来映射那些已经用来改变随机
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#define MATRIX_SIZE 9
#define MAX_NUM 9
void solve_sudoku(int board[MATRIX_SIZE][MATRIX_SIZE]);
void print_sudoku(int board[MATRIX_SIZE][MATRIX_SIZE]);
int rowCheck(int num, int board[][MATRIX_SIZE], int row);
int columnCheck(int num, int board[][MATRIX_SIZE], int row);
int squareCheck(int num, int board[][MATRIX_SIZE], int row, int col);
int giveNum(void);
void main()
{
srand(time(NULL));
int board[MATRIX_SIZE][MATRIX_SIZE];
/*{
0,0,0,0,0,4,0,0,0,
0,6,8,0,0,0,5,0,0,
0,2,0,0,0,0,0,7,6,
6,0,0,0,0,0,8,9,0,
0,0,5,2,6,0,0,0,0,
0,0,0,9,0,0,1,0,0,
0,0,0,0,0,7,0,5,0,
0,4,0,0,0,0,0,0,1,
0,0,0,0,5,1,4,0,0
};*/
for (int row = 0; row < MATRIX_SIZE; row++)
for (int col = 0; col < MATRIX_SIZE; col++)
board[row][col] = -1;
solve_sudoku(board);
print_sudoku(board);
}
void solve_sudoku(int board[MATRIX_SIZE][MATRIX_SIZE])
{
int rowCh, colCh, sqrCh, num, square = 0;
for (int row = 0; row < MATRIX_SIZE; row++)
{
for (int col = 0; col < MATRIX_SIZE; col++)
{
if (square > 2)
square = 0;
while(1)
{
num = giveNum();
rowCh = rowCheck(num, board, row, col);
if (!rowCh)
continue;
colCh = columnCheck(num, board, row, col);
if (!colCh)
continue;
sqrCh = squareCheck(num, board, row, col-square);
if (!sqrCh)
continue;
break;
} //while (!rowCh || !colCh || !sqrCh);
square++;
board[row][col] = num;
}
}
}
void print_sudoku(int board[MATRIX_SIZE][MATRIX_SIZE])
{
printf("Sudoku solution:\n");
for (int i = 0; i < MATRIX_SIZE; i++)
{
for (int j = 0; j < MATRIX_SIZE; j++)
printf("%d ", board[i][j]);
printf("\n");
}
}
int giveNum(void)
{
int num = rand() % MATRIX_SIZE + 1;
return num;
}
int rowCheck(int num, int board[][MATRIX_SIZE], int row)
{
for (int col = 0; col < MATRIX_SIZE; col++)
{
if (num == board[row][col])
return 0;
}
return 1;
}
int columnCheck(int num, int board[][MATRIX_SIZE], int col)
{
for (int row = 0; row < MATRIX_SIZE; row++)
{
if (num == board[row][col])
return 0;
}
return 1;
}
int squareCheck(int num, int board[][MATRIX_SIZE], int row, int col)
{
for (int i = row; i < row + sqrt(MATRIX_SIZE); i++)
for (int j = col; j < col + sqrt(MATRIX_SIZE); j++)
if (board[i][j] == num)
return 0;
return 1;
}
\define\u CRT\u SECURE\u NO\u警告
#包括
#包括
#包括
#包括
#定义矩阵_大小9
#定义最大数量9
void solve_数独(int board[MATRIX_SIZE][MATRIX_SIZE]);
无效打印数独(集成电路板[矩阵大小][矩阵大小]);
int rowCheck(int num,int BOUND[][矩阵大小],int row);
int columnscheck(int num,int board[][MATRIX_SIZE],int row);
int平方检查(int num,int BOUND[][矩阵大小],int行,int列);
int-giveNum(无效);
void main()
{
srand(时间(空));
int板[矩阵大小][矩阵大小];
/*{
0,0,0,0,0,4,0,0,0,
0,6,8,0,0,0,5,0,0,
0,2,0,0,0,0,0,7,6,
6,0,0,0,0,0,8,9,0,
0,0,5,2,6,0,0,0,0,
0,0,0,9,0,0,1,0,0,
0,0,0,0,0,7,0,5,0,
0,4,0,0,0,0,0,0,1,
0,0,0,0,5,1,4,0,0
};*/
对于(int row=0;row2)
平方=0;
而(1)
{
num=giveNum();
rowCh=行检查(num、board、row、col);
如果(!rowCh)
继续;
colCh=列检查(num、board、row、col);
如果(!colCh)
继续;
sqrCh=squareCheck(数字、电路板、行、列平方);
如果(!sqrCh)
继续;
打破
}//而(!rowCh | | |!colCh | |!sqrCh);
square++;
板[行][列]=num;
}
}
}
无效打印数独(int板[矩阵大小][矩阵大小])
{
printf(“数独解决方案:\n”);
对于(int i=0;i
我强烈怀疑,使用纯随机方法是否会带来好运。有如此多的组合,所以找到有效解决方案的机会非常小。相反,你很可能会在一个死锁中结束,没有有效的数字放在当前位置。。。然后你就有了一个无止境的循环
无论如何。。。这里有一个bug:
要使squareCheck
功能工作,需要col
和row
标识左上角。对于col
您确保使用square
,但对于row
您不使用
换句话说,你的支票不对
而不是使用“<代码>方块< /代码>方法”考虑将这些行放在函数的开始处:
row = row - (row % 3);
col = col - (col % 3);
这里有一种生成随机数独子的方法
// Check that no number 1..9 is present twice in a column
int colok(int s[][9])
{
for (int col=0; col<9; ++col)
{
for (int n=1; n<=9; ++n)
{
int cnt = 0;
for (int i=0; i<9; ++i)
{
if (s[i][col] == n)
{
if (cnt > 0) return 0;
cnt = 1;
}
}
}
}
return 1;
}
// Check that no number 1..9 is present twice in a 3x3 block
int blockok(int s[][9])
{
for (int row=0; row<9; row += 3)
{
for (int col=0; col<9; col +=3)
{
for (int n=1; n<=9; ++n)
{
int cnt = 0;
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
if (s[i + row][j + col] == n)
{
if (cnt > 0) return 0;
cnt = 1;
}
}
}
}
}
}
return 1;
}
void p(int s[][9])
{
for (int i=0; i<9; ++i)
{
for (int j=0; j<9; ++j)
{
printf("%d ", s[i][j]);
}
puts("");
}
}
#define MAX_LOOP 10000000
void makerow(int s[][9], int r)
{
int loops = 0;
while(1)
{
++loops;
// FY Shuffle row (this ensures that rows are always valid)
int a[] = {1,2,3,4,5,6,7,8,9};
int max = 8;
while(max)
{
int t = rand() % (max + 1);
int tmp = a[t];
a[t] = a[max];
a[max] = tmp;
--max;
}
// Save row
for (int i=0; i<9; ++i)
{
s[r][i] = a[i];
}
// Check whether it's valid
if (colok(s) && blockok(s))
{
// It's valid so stop here
break;
}
// Stop if too many loops
if (loops > MAX_LOOP)
{
puts("I'm so tired...");
exit(1);
}
}
printf("loops %d\n", loops);
}
int main(void)
{
srand((int)time(0));
int s[9][9] = { 0 };
for (int i=0; i<9; ++i)
{
printf("Make row %d\n", i);
makerow(s, i);
}
p(s);
return 0;
}
但请注意……可能无法生成解决方案。。那么输出是:
Make row 0
loops 1
Make row 1
loops 37
Make row 2
loops 2957
Make row 3
loops 16
Make row 4
loops 2253
Make row 5
I'm so tired...
有一个循环while(1)
,您在其中选择一个随机数并确定它在当前位置是否有效。
在这里很可能走到死胡同。
您可以轻松地填写数字,这些数字虽然单独有效,但无法解决难题
如果你被“卡住”或检测到它会被卡住,你需要一些回溯的方法
“通用”方法是保存一个9x9矩阵集,该矩阵集包含1-9的子集,这些子集是未试验的值。设置值(在开始时)或尝试值(在求解过程中)时,可以检查约束并从其列、行和正方形中删除正在尝试的值
从9x9网格开始,将所有单元格初始化为全范围[1-9]。
如果将单元格设置为(比如)5,则从该列、行和子正方形中的所有单元格中删除5
如果这使得任何一个单元格的集合为空,那么这个谜题就无法解决
求解时,仅从“剩余可能值”集合中选取,而不是从rand[1-9]中选取
然而,试验仍然可能使谜题无法解决,需要返回一个(或多个)细胞才能再次出现
实现这一点的简单方法是递归。但这被演习排除了。
因此,看起来需要某种撤销堆栈。为了避免递归,您可以尝试导航解决方案
Make row 0
loops 1
Make row 1
loops 37
Make row 2
loops 2957
Make row 3
loops 16
Make row 4
loops 2253
Make row 5
I'm so tired...
int giveNum(void)
{
int static num = 1;
if (num > 9)
num = 1;
return num++;
}