这是我学习C语言半个月左右写的一个程序,可能有很多不合理之处,请大家指出.
数独按行输入,空格,换行符,字母等非数字不干扰输入,你只需要按照顺序一行一行的输入即可,空格假定为零.
#include <stdio.h>
#include <ctype.h>
void input_sudoku(int (*p_sudoku)[9]);
void output_sudoku(const int (*p_sudoku)[9]);
int check_rationality(const int (*p_sudoku)[9], int row, int column, int n);
int solve_sudoku(int (*p_sudoku)[9]);
int main(void)
{
int sudoku[9][9];
int state;
input_sudoku(sudoku);
output_sudoku(sudoku);
state = solve_sudoku(sudoku); // 求解数独
if (state)
{
printf("有解!\n");
output_sudoku(sudoku);
}
else
{
printf("无解!\n");
}
// scanf(" %d ",&state);
return 0;
}
void input_sudoku(int (*p_sudoku)[9]) // 输入数独
{
char temp;
printf("请输入数独:\n");
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
while (!isdigit(temp = getchar())) // 检查输入是否是数字
{
continue;
}
p_sudoku[i][j] = (int)temp - '0'; // 字符转为数字
}
printf("第%d行已输入完毕.\n", i + 1);
}
}
void output_sudoku(const int (*p_sudoku)[9]) // 输出数独
{
printf("数独为:\n");
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
printf("%d ", p_sudoku[i][j]);
}
printf("\n");
}
}
int check_rationality(const int (*p_sudoku)[9], int row, int column, int num) // 检查该数字能否放在这个位置
{
int i, j, center_row, center_column;
for (j = 0; j < 9; j++) // 检查该数字是否会与该行重复
{
if (p_sudoku[row][j] == num)
{
return 0;
}
}
for (i = 0; i < 9; i++) // 检查该数字是否会与该列重复
{
if (p_sudoku[i][column] == num)
{
return 0;
}
}
center_row = row / 3 * 3; // 九宫左上角行索引
center_column = column / 3 * 3; // 九宫左上角列索引
for (i = center_row; i <= center_row + 2; i++) // 检查是否与九宫中数字重复
{
for (j = center_column; j <= center_column + 2; j++)
{
if (p_sudoku[i][j] == num)
{
return 0;
}
}
}
return 1;
}
int solve_sudoku(int (*p_sudoku)[9])
{
struct Idex // 定义结构体,用于存储空白格的信息
{
int row;
int column;
int state; // 该格起始候选数
};
struct Idex arr_idex[81]; // 供存放空白格索引
int i, j;
int end = -1, now = 0; // end代表最后一个空格索引,now代表当前正在操作的空格
for (i = 0; i < 9; i++) // 找到所有空格
{
for (j = 0; j < 9; j++)
{
if (p_sudoku[i][j] == 0)
{
end++;
arr_idex[end].row = i;
arr_idex[end].column = j;
arr_idex[end].state = 1;
}
}
}
for (now = 0; now <= end;) // 循环求解
{
if (arr_idex[now].state > 9) // 如果候选数超出范围(情况发生在第K个格子填九,第k+1个格子无数可填时,需要连续回溯两次)
{
if (now == 0) // 这是起始空白格,说明该数独无解
{
return 0;
}
else // 不是起始空白格,再次回溯
{
arr_idex[now].state = 1; // 候选数复位
p_sudoku[arr_idex[now].row][arr_idex[now].column] = 0; // 该格置为0(空格)
now--; // 求解上一个空白格
continue;
}
}
for (i = arr_idex[now].state; i <= 9; i++) // 从起始候选数到9,依次遍历
{
if (check_rationality(p_sudoku, arr_idex[now].row, arr_idex[now].column, i)) // 该数字合理则填入
{
arr_idex[now].state = i + 1; // 更新起始候选数以供下一次使用
p_sudoku[arr_idex[now].row][arr_idex[now].column] = i;
now++; // 求解下一个单元格
break;
}
else if (i == 9) // 该格已遍历完但没有合适的数
{
arr_idex[now].state = 1; // 回溯,同上
p_sudoku[arr_idex[now].row][arr_idex[now].column] = 0;
now--;
}
}
}
return 1; // 所有格子均已填完,即数独求解成功,返回1
}