C语言程序解数独问题

一直想写个程序解数独问题但是一直没有时间,趁这两天放寒假了终于可以来写一写程序了。程序的运行结果还是比较理想的,Ubuntu里面“Very hard”级别被秒杀。所谓的四分钟其实我有两分钟在输入,两分钟在输出什么的……这里陈述一下主要思想,希望能与高手交流~~完整的代码我上传在我的资源里面了。

要解决数独问题,想来想去,只能穷举了。但是我肯定不能用简单的穷举,要是完全穷举的话估计是个阶乘级的复杂度,这种程序写出来也是没有意义的,必须想一个好一点的办法。

首先我需要确定一些数据结构。肯定我们这里需要一个数组,9*9的,来存放数独的表格(当然我实际选用的是一个含81个元素的一维数组);除此之外,考虑到要经常查询某个元素是否可以放置在某个位置上,我们还需要一个“集合”。这里我选用的是位图集合,因为有我以前写好的现成的函数可以用。我总共用了27个集合,分别表示9行、9列和9个九宫格。Main函数的伪代码框架如下所示:

int main(void) {

      struct my_bitmap set[27];

      int i, j, cells[81], *array;

      //自己定义的位图集合

      //0-8 for rows 9-17 for columns 18-26 for cells

      init();

      //读初始化文件,初始化数组、集合

      array= my_try();

      //递归的解问题

      display();

      return 0;

}

那么要如何解决问题呢?我采用的是简单的贪心算法,每次找当前含有最多信息的未被填满的那个“单元”(这里所谓的“单元”指的是一行或者一列或者一个九宫格),从这个单元里面找出一个未被被填充的空格,从1-9依次尝试,如果i可以被填入这个空格,那么就将其填入,如果不能就换i+1尝试。这时我们就可以递归的解决这个新产生的问题了。当只剩下一行或一列未被填满时,可以算是Basecase了,因为对于这一行的每一列(或者这一列的每一行),都只有一个元素未被填入,这个元素必然是唯一的,可以直接解出来。于是我们可以写出这里递归的主体框架了:

int* my_try(int* array) {

      int max_notfull, i, r, c, flag, pos;

      int *ret;

      max_notfull = get_max_notFull();

      //找出尚未被填满的“单元”中含有最多信息的单元

      if (/*trival case*/)

      //如果是前面所说的“basecase

             return trival_solution();

      pos = get_nextIdx(max_notfull, array,);

      //从当前单元中获取第一个未被填充的空格位置

      if (pos == -1)

             return array;

      //表示已全部填满

      r = pos / 9;

      c = pos % 9;

      for (i = 1; i < 10; i++) {

             if (mark(r, c, i, array) != -1) {

                    //尝试将i放入第r行第c列这个位置,返回-1表示放入

//不成功,存在冲突

                    ret = my_try(array);

                    //递归解决问题

                    if (ret)

                    /*ret  != 0 说明成功解决问题

                      返回0 说明这种尝试不可能成功

                    */

                           return ret;

                    erase(r, c, array);

                    //从数组中删除这次添加值,尝试下一次

             }

      }

      //全部尝试完,说明无解,返回0

      return 0;

}

       这里面有一些函数我就不说明他们的具体实现了,函数的含义在注释中都说明了,这里帖一下头文件 function.h

#ifndef FUNCTION_H_

#define FUNCTION_H_

#include "bitmap.h"

void init(int* array, struct my_bitmap* sets);

int get_max_notFull(struct my_bitmap* sets);

//Return index of the unit which is not full and contains the

//most information. 0-8 for rows, 9-17 for colunms and 18-26 for cells.

//One bit among 16-18 is marked, to indicate that it is the last unit

//which is not full.

int mark(int row, int colunm, int value, int* array, struct my_bitmap* sets);

//put value in the position row*colunm, return value

//or -1 if fail(already occupied or invalid parameter).

int erase(int row, int colunm, int* array, struct my_bitmap* sets);

//erase the remark in the particular postion; return 0

//or return -1 if fail(not occupied)

int get_rowset_index(int row, int colunm);

//return 0-8, depends on row

int get_colset_index(int row, int colunm);

//return 9-17, depends on colunm

int get_cellset_index(int row, int colunm);

//return 18-27

int get_nextIdx(int unit, int* array, struct my_bitmap* sets);

//Find the first index in this unit which is not occupied

//return -1 if not find;

int* my_try(int* array, struct my_bitmap* sets);

int* trival_solution(int unit, int flag, int* array, struct my_bitmap* sets);

#endif /* FUNCTION_H_ */

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值