《编程之美》书上并没有这一节,而是我根据“构造数独”一节推广而来的。上一篇我用矩阵的初等变换来构造数独,这一篇我就用DFS(其实我觉得叫递归+回溯更贴切)来求解数独。
具体的步骤我就不啰嗦了,不了解的可以参考任何一本算法书或数据结构的书。递归求解数独并不像网上一些说人的那么慢(一个比较难的数独也是瞬间就解出来了),更不会有栈溢出,处理不当就另当别论。
这个程序采用文件输入,输入的数据格式为:
004003010
000250000
080000726
020030000
760000805
350867000
905084007
032700900
000905300
其中0表示要填的空。为了操作方便我用一维数组来表示二维数组。
最后要说明的是,当所有都是要填的空时就相当于构造数独了。当然,这个程序只能构造出一种数独,要使每次构造出不同的数独就需要在算法中加入随机因子了。
CODE
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <malloc.h>
void Print(char *grid);
int Next(int index);
char* GetAllowable(int index, int* count);
void Solve(int index);
bool completed = false; //标记是否完成
bool nosolution = false; //标记是否无解
int startIndex = 0;
char solution[81]; //保存数独
int main(int argc, char *argv[])
{
FILE* file;
char ch;
int i = 0;
//从文件读入
if((file = fopen("problem.txt","r")) == NULL)
exit(0);
while((ch = fgetc(file)) != EOF)
{
if(ch != '/n')
{
*(solution + i) = ch;
i++;
}
}
fclose(file);
puts("题目:");
Print(solution);
startIndex = Next(-1);
Solve(startIndex);
if(!nosolution) //有解
{
puts("/n解答:");
Print(solution);
}
else
{
puts("无解!");
}
puts("");
system("pause");
return 0;
}
//输出数独
void Print(char *grid)
{
for(int i = 0; i < 81; ++i)
{
printf("%2c", grid[i] == '0' ? '_' : grid[i]);
if(i % 9 == 8) printf("/n");
}
}
//返回所有在index位置请允许的数字,count为总数
char* GetAllowable(int index, int* count)
{
int r = index / 9; //行
int c = index % 9; //列
bool f[10];
for(int i = 1; i < 10; ++i) f[i] = true;
for(int i = 0; i < 9; ++i)
{
f[solution[r * 9 + i] - '0'] = false; //行
f[solution[9 * i + c] - '0'] = false; //列
f[solution[(r / 3 * 3 + i / 3) * 9 + c / 3 * 3 + i % 3] - '0'] = false; //小九宫格
}
int n = 0;
for(int i = 1; i < 10; ++i)
if(f[i]) n++;
char* v = NULL;
if(n > 0)
{
v = (char*)malloc(sizeof(char) * n);
if(v == NULL) exit(0);
for(int i = 1, j = 0; i < 10; ++i)
if(f[i]) v[j++] = i + '0';
}
*count = n;
return v;
}
//求解主函数
void Solve(int index)
{
int n, next;
char* v = GetAllowable(index, &n);
if(n == 0) return;
for(int i = 0; i < n; ++i)
{
solution[index] = v[i];
if((next = Next(index)) == 81) //完成
{
completed = true;
}
else
{
Solve(next); //递归
}
if(completed == true)
{
free(v);
return;
}
}
free(v);
solution[index] = '0';
if(index == startIndex) //无解
{
nosolution = true;
}
}
//找下一个要填的空格
int Next(int index)
{
while(++index < 81 && solution[index] != '0');
return index;
}
----------------------------------------------------------