如何在C中填充空的数独板

如何在C中填充空的数独板,c,C,我接到一个任务,写一个程序,填充一块空的数独板并打印出来 我们拥有的工具只有函数、数组和指针。没有递归,没有搜索和排序算法来提高时间复杂度 到目前为止,我想对电路板使用二维数组,并在嵌套的“for”循环中遍历每一行 每次我用随机函数取一个数字,检查一行、一列和一个正方形(3X3),如果它们都通过了,我就填充这个数字 我的问题是,这样代码需要很长时间才能解决,我不知道我是否做对了。我还没有看到我的代码的解决方案,即使让它运行5分钟以上。我想也许可以用一个1-9的数字直方图来映射那些已经用来改变随机

我接到一个任务,写一个程序,填充一块空的数独板并打印出来

我们拥有的工具只有函数、数组和指针。没有递归,没有搜索和排序算法来提高时间复杂度

到目前为止,我想对电路板使用二维数组,并在嵌套的“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++;
}