您的位置:首页 > 编程语言 > C语言/C++

c语言编程:优化回溯解数独程序

2012-07-22 17:49 411 查看
上次在博客上发了一篇《C语言:回溯解数独程序》。实在很粗糙,效率相当差。正如在群里一位朋友说的:

你能不能别像傻瓜式一样从左到右从上到下这样搜索呢?如果你这样,我出第一行是空的数独题,那你不就要算死了?

听了这话也怪不好意思的,而且他确实给了我下面这么一个题目(是无解的),但我的题目却是卡住很久都没算出来。

[code lang="js"]
0000004900
0000000000
0000000000
0007090000
0080000000
0000607000
1005300002
00000048000

原本再设计程序的时候findPosition函数是找出目前数字相对密集的位置,因为从这里开始计算量是最少的,但是由于当时并没有什么好的实现方法,自己又想早点将数独程序解出来,就采用上面说的最傻瓜的从上面第一个空位置开始。如果是一个正常的题目的话解题时间还能接受,但是如果像他给我这个无解的题目的话就不行了。所以我想还是只有先将findPosition优化一下,找出数字相对密集的地方。优化后的代码如下:

[code lang = "js"]
void findPosition(int *line,int *row)
{
int maxnum,maxrow;
int i,j;
maxnum = maxrow = -1;  //
//找到已填好数字最多的一行
for(i = 1;i < 10;i++){
if(9 == sd.line_count[i])
continue;
if(sd.line_count[i] > maxnum){
maxnum = sd.line_count[i];
*line = i;
}
}
//找到那一行没有填数且列填好数字最多的位置
for(i = 1;i < 10;i++){
if(0 == sd.data[*line][i]){
if(sd.row_count[i] > maxrow){
maxrow = sd.row_count[i];
*row = i;
}
}
}
}

这样之后,代码的效率的确高了。上面的那个题目我统计了一下时间是这个多(采用clock()函数):

[code lang="js"]
test.txt
We don't find an answer.
It cost 0.010000s.

然后我又找了几个题目来算,时间也减少了很多,下面举一个例,题目是:

[code lang="js"]
0 6 1 0 3 0 0 2 0
0 5 0 0 0 8 1 0 7
0 0 0 0 0 7 0 3 4
0 0 9 0 0 6 0 7 8
0 0 3 2 0 9 5 0 0
5 7 0 3 0 0 9 0 0
1 9 0 7 0 0 0 0 0
8 0 2 4 0 0 0 6 0
0 4 0 0 1 0 2 5 0

下面是结果:

[code lang="js"]
c:\\test.txt
We find an answer.
7 6 1 9 3 4 8 2 5
3 5 4 6 2 8 1 9 7
9 2 8 1 5 7 6 3 4
2 1 9 5 4 6 3 7 8
4 8 3 2 7 9 5 1 6
5 7 6 3 8 1 9 4 2
1 9 5 7 6 2 4 8 3
8 3 2 4 9 5 7 6 1
6 4 7 8 1 3 2 5 9

We find an answer.  It cost 0.000000s.


我知道这个解法还有一定的缺陷,因为对回溯的不熟悉,我不是很清楚findposition还可以怎样优化。但是我知道优化的方法还有很多,所以这篇文章是(一)。

下面再说下对上次程序的小改动:

init函数应该检查输入是否合法,就是检查一行或一列或一个3*3小九宫格是不是有相同的数字,这个很简单,改动后的代码如下:

[code lang="js"]
//把从文件中读取的数字保存进题目信息
int initSodu(int a[81],psodu ps)
{
if(NULL == ps)
return 0;
int i,line,row;
for(i = 0;line = (i/9 + 1),row = (i % 9 + 1),i < 81;i++){
if((ps->data[line][row] = a[i]) != 0){//该位置已填数字才有信息读啊
if(testThisNumber(line,row,a[i]))
return 0;
ps->line_number[line][a[i]] = 1;
ps->row_number[row][a[i]] = 1;
ps->small_number[TOSMALL(line,row)][a[i]] = 1;

ps->line_count[line]++;
ps->row_count[row]++;
ps->small_count[TOSMALL(line,row)]++;
ps->achieve_number++;
}
}
return 1;
}


还有readFile函数可以这样改,简洁很多(也是上面那个网友说的,谢谢了)

[code lang="js"]
//从文件中读取数独题目
int readFile(char *filename,int a[])
{
FILE *fp = NULL;
int i = 0;
char c;
//文件是否成功打开
if((fp = fopen(filename,"r")) != NULL){
//从文件中读取数字,读到文件尾
while((c = fgetc(fp)) != EOF){
if(c >= '0' && c <= '9' && i < 81)
a[i++] = c - '0';
}
fclose(fp);  //关闭文件
}
else
return 0;        //文件读取失败则返回
if(i != 81)
return 0;

return 1;  //文件读取成功
}


最后我想说的是今天群里有位朋友说我的博客太丑了,而且也不更新。他搜索site:www.dabentu.com搜不出,于是说博客太丑了百度都不收录 的。我马上搜了一下site:dabentu.com。有120多条,马上截图过去。虽然我不是很清楚这方面的事,但我也知道dabentu.com才是 顶级域名。自己选择这款主题就是因为喜欢,我也不在乎他人评价好坏,而且博客不收录没访问也没关系,我只是用来记录自己的学习经历,用来上传自己的一些代 码而已。说我不更新的话,确实,好几天没更新了。这几天一直不知道有什么好写的,觉得就算写了对别人也没太大价值,就不去费那个时间了。

好了,这就是这篇文章的内容(全文完)

转载自大笨兔http://dabentu.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: