数据格式
3 2 6 7 8 4 5 9 1
1 4 5 2 3 9 6 7 8
7 8 9 1 5 6 2 3 4
2 1 3 4 6 5 7 8 9
4 5 7 8 9 1 3 2 6
6 9 8 0 2 7 1 4 5
5 3 1 9 4 2 8 6 7
8 6 4 5 7 3 9 1 2
9 7 2 6 1 8 4 5 3
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define CORRECT 0
#define WRONG -1
#define MAXNUM 1000 /*数独游戏个数*/
/* 构造完成标志 */
bool sign = false;
int checkSudoku(const char a[][COL]){
int i,j,x,y;
for( i = 0; i < ROW ; i++){
for(j = 0 ; j < COL ; j++){
for(x = 0 ; x < COL ; x++)
if(a[i][x] == a[i][j] && x != j )
return WRONG;
for(x = 0 ; x < ROW ; x++)
if(a[x][j] == a[i][j] && x != i )
return WRONG;
for(x = i/3*3 ; x < i/3*3+3 ; x ++)
for(y = j/3*3 ; y < j/3*3+3 ; y++)
if(a[x][y] == a[i][j] && (x != i && y != j))
return WRONG;
}
}
return CORRECT;
}
void printSudoku(const char a[][COL]){
int i,j;
printf("\n ┌────┬────┬────┐\n");
for( i = 0 ; i < ROW ; i++){
if(i != 0 && i%3 == 0) printf(" ├────┼────┼────┤\n");
printf(" │");
for( j = 0 ; j < COL ; j++){
if(j != 0 && j%3 == 0) printf(" │");
if(a[i][j])
printf(" %d",a[i][j] - '0');
else printf(" ");
}
printf(" │\n");
}
printf(" └────┴────┴────┘\n");
}
void readFromFile(char a[][COL], const char filename[]){
// To Be Solved
// 从文件filename中读取到的数独初盘存储到数组a[][COL]中
int i = 0, j = 0, num = 81;
char c = 0;
FILE* fp = fopen(filename, "r");//读文件
while (num)
{
fscanf(fp, "%c", &c);
if (c == 10 || c == 32)
{
continue;
}
a[i][j] = c;
num--;
j++;
if (j >= 9)
{
j = 0;
i++;
}
}
fclose(fp);
}
/* 判断key填入n时是否满足条件 */
bool Check(int arr[ROW][COL], int n, int key)
{
/* 判断n所在横列是否合法 */
for (int i = 0; i < 9; i++)
{
/* j为n竖坐标 */
int j = n / 9;
if (arr[j][i] == key) return false;
}
/* 判断n所在竖列是否合法 */
for (int i = 0; i < 9; i++)
{
/* j为n横坐标 */
int j = n % 9;
if (arr[i][j] == key) return false;
}
/* x为n所在的小九宫格左顶点竖坐标 */
int x = n / 9 / 3 * 3;
/* y为n所在的小九宫格左顶点横坐标 */
int y = n % 9 / 3 * 3;
/* 判断n所在的小九宫格是否合法 */
for (int i = x; i < x + 3; i++)
{
for (int j = y; j < y + 3; j++)
{
if (arr[i][j] == key) return false;
}
}
/* 全部合法,返回正确 */
return true;
}
/* 深搜构造数独 */
int DFS(int arr[ROW][COL], int n)
{
/* 所有的都符合,退出递归 */
if (n > 80)
{
sign = true;
return 0;
}
/* 当前位不为空时跳过 */
if (arr[n / 9][n % 9] != 0)
{
DFS(arr, n + 1);
}
else
{
/* 否则对当前位进行枚举测试 */
for (int i = 1; i <= 9; i++)
{
/* 满足条件时填入数字 */
if (Check(arr, n, i) == true)
{
arr[n / 9][n % 9] = i;
/* 继续搜索 */
DFS(arr, n + 1);
/* 返回时如果构造成功,则直接退出 */
if (sign == true)
return 0;
/* 如果构造不成功,还原当前位 */
arr[n / 9][n % 9] = 0;
}
}
}
}
int Solve(char arr[ROW][COL], int row, int col)
{
int i, j;
char n = 48;
int flag_next = 0;
int next_row = 0, next_col = 0;
while (1) {
next_num:
++n;
if (n > 57) break;
// 判断行重复
for (j = 0; j < ROW; j++) {
if (arr[row][j] == n) {
goto next_num;
}
}
// 判断列重复
for (i = 0; i < COL; i++) {
if (arr[i][col] == n) {
goto next_num;
}
}
/* 判断所在小九宫格重复*/
int x = (row / 3) * 3;
int y = (col / 3) * 3;
for (i = x; i < x + 3; i++) {
for (j = y; j < y + 3; j++) {
if (arr[i][j] == n) {
goto next_num;
}
}
}
//该单元可以填充
arr[row][col] = n;
//如果9宫格已填满,完成,这里不考虑有多解的情况
flag_next = 0;
for (i = 0; i < ROW; i++)
for (j = 0; j < COL; j++)
if (arr[i][j] == '0') {
next_row = i;
next_col = j;
flag_next = 1;
break;
}
if (!flag_next)
{
return 1;
}
//否则继续填下一个未填充的格子
if (!Solve(arr, next_row, next_col)) {
//数独填写完毕就不重写以前留下的足迹
arr[row][col] = 48;
continue;//一直到本次循环完毕,直接跳出循环后,执行最后的 return 0;
}
else
return 1;//成功的标志,一路返回
}
return 0;
}
void solveSudoku(const char a[][COL], char b[][COL]){
// To Be Solved
// 参数const char a[][COL]表示初盘二维数组;
// 参数char b[][COL]表示解的二维数组。
int row = 0, col = 0;
int flag = 0;
int arr[ROW][COL];
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++)
{
b[i][j] = a[i][j];
arr[i][j] = b[i][j] - '0';
}
}
//for (int i = 0; i < ROW; i++)
// for (int j = 0; j < COL; j++)
// if (b[i][j] == '0') {
// row = i;
// col = j;
// flag = 1;
// break;
// }
DFS(arr, 0);
//Solve(b, row, col);
//将int数组转换为char
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
b[i][j] = arr[i][j] + '0';
}
}
}
int main(){
char starting_grid[ROW][COL]={0};
char result[ROW][COL]={0};
char filename[50];
int rr;
double time_from, time_to, time_sum = 0;
int i;
for( i = 0; i < MAXNUM ; i++){
sign = false;
sprintf(filename,"sudoku\\%04d.txt",i);
readFromFile(starting_grid,filename);
printf("\n\n *%4d *",i);
printSudoku(starting_grid);
time_from = clock();
solveSudoku(starting_grid,result);
time_to = clock();
time_sum += time_to - time_from;
printSudoku(result);
rr = checkSudoku(result);
if( rr == WRONG){
printf("Something goes wrong...\n");
return WRONG;
}
else printf(" Correct!!!\n");
printf(" ==============================");
}
printf("\n Congretulations! ToTal Time:%fs\n",time_sum / CLOCKS_PER_SEC);
return 0;
}