1、数独sudoku的生成与破解数独(sudoku)的生成与破解一、 数独游戏的规则数独(sudoku),起源于瑞士,于1970 年代由美国的一家数学逻辑游戏杂志首先发表,当时名为Number Place。及后在日本大力推广下得以发扬光大,于1984 年取名“数独”,即“独立的数字”的省略,在一个99的方格中,有81个小方格组成,然后又分9个大块,每块由3x3的方格组成,就是中国的九宫阵。游戏规则:“九宫阵”是一个99的方阵,它是由九个“九宫格”(图中黑色实线围住的33的方阵)构成的,每个九宫格又是由九个小格子构成的,在每个小格子里面填上19中的数字,使得每个数字在“九宫阵”的每行、每列、每个九宫
2、格中均只出现一次。游戏开始前会有一些格子上写好了数,你需要在剩下的格子里填数,真到把所有格子填满,并且要求,任何一行或一列或者一个小九宫中没有相同的数字,当然你只能用19之间的9个数字。如下图就是一个数独游戏。题 目 答 案二、 数独(sudoku)的生成基本思路:为了保证生成的数独一定有解,就要先得到了一个完整的数独(可以想象所有满足条件的组合是很多的),然后从格子里面随机挖掉一些数字就可以了。那么如何得到一个完整数独呢?我们可以这样想先给每一行(或列)填入一个不同的数,然后用“数独破解”的方法去完成,这就OK了。步骤如下:1 在第i行 (i=08)随机找个格子mapij (j=08)填入本
3、行数i+1;2 用“数独求解”(见数独(sudoku)的生成)的方法产生一个完整数独;3 从81个格子里面随机挖去n个数字。三、 数独(sudoku)的破解我们可以想象每个格子可填入的数字是可以得知的,但这不是唯一的,应先填入哪个数字就是个问题,另外先填哪一个格子也是不确定的,那么如何开始填才最佳呢?这里我们需要引入一个概念格子的不确定度,一个格子可以填的数字的个数称为它的不确定度。所以我们需要用递归下面的做法:我们去寻找不确定度最小的格子;确定这个格子可以填的数字;填入一个数字后,递归。随着填上去数字增多,剩余空格上的不确定度也会降低,如果某个格子上的不确定度降到1,那这个格子可以先确定下来
4、,如果降到了0,哦,非常遗憾,在前面的填数中一定是填错了,你不得不回退。四、 唯一解的问题这里有一问题,我们需要的是我们生成的数独是否具有唯一解?是的,按上面数独生成的过程是不能保证的。为了保证数独有唯一解,应该从哪儿考虑呢?我的思路是:从完整数独中挖格子的过程中去分析。根据数独破解的方法,在破解过程中每次要寻找的最小不确定度的那个格子,如果每次找到的这个格子可填的数字都仅为个(最小不确定度为)时,那么得到的解一定唯一。这样就给我们启发,我们在挖格子时,每挖一个格子,也去检测最小不确定度的格子的不确定度。如果这个不确定度大于,则就要重新这次挖格子。另外也有可能挖遍所有的格子(程序中我设的上限是
5、81次)也没有合适解时,那么要中止这次操作,这时就要从重新生成一个数独。五、 游戏的难易程序这个问题我是这么考虑的,只要生成的数独中的空格数(blank)越多,那么就越难。所以在些程序中我设置三个级别:容易:blank=3335;中等:blank=3638;困难:blank=3941;六、 源程序#ifndef SUDOKU_RICK_0701_#define SUDOKU_RICK_0701_class CSudokuint map99;int blanks;int smod;int solves;int check(int,int,int*);void dfs();public:enumA
6、NY=0,ALL=1;CSudoku(int);CSudoku:CSudoku(int *data);void SudokuGenerator(int); / 随机生成数独,n越大越难void SudokuGenerator(int *data);/ 人工指定数独/virtual CSudoku();void display();/ 显示数独int resolve(int mod=ALL);/ 解数独void analyze(); ;#endif#include stdio.h#include stdlib.h#include time.h#include iostream#include i
7、omanip /要用到格式控制符using namespace std;CSudoku:CSudoku(int n)int j;j=rand()%3;blanks=n+j;SudokuGenerator(blanks); coutendl随机数独:endlendl;/cout(空格子数为blanks)endl;display();coutpress enter to continue! endl;getchar();getchar();while(1)cout % endl;cout % 请选择您的操作: % endl;cout %=% endl;cout % % endl;cout % 1.
8、 显示当前数独 % endl;cout % 2. 分析求解 % endl;cout % 3. 查看结果 % endl;cout % 4. 返 回 % endl;cout % % endl;cout % select;switch (select)case 1:coutendl当前随机数独: endl; display();coutpress enter to continue! endl;getchar();getchar();break;case 2:analyze(); break;case 3:coutendl显示结果: endl;resolve();coutpress enter to
9、 continue! endlendl;getchar();getchar();break;case 4: return;default:cout输入错误,请重新输入.endl;break;CSudoku:CSudoku(int *data)SudokuGenerator(data);coutendl已知数独为: endl; display();coutpress enter to continue! endl;getchar();getchar();analyze();void CSudoku:SudokuGenerator(int n)int i,j;int mark10;srand(ti
10、me(0);/每一行i产生一个随机位置(列j)并置为当前行值i+1,0=i,j=8。dofor(i=0;i9;+i)for(j=0;j9;+j)mapij=0;j=rand()%9;mapij=i+1;/display(); while(!resolve(ANY); /生成完整的随机Sudoku表格/ 挖窟窿for(int k=0;kn;+k)int tmp,flag=0,sum=1;do/ coutsum=sum81)SudokuGenerator(n); return;if (flag=1)mapij=tmp;doi=rand()%81;j=i%9;i=i/9;while (mapij=0
11、);tmp=mapij;mapij=0;flag=1;while (check(i,j,mark)1);void CSudoku:SudokuGenerator(int *data)int *pm=(int*)map;for(int i=0;i81;+i)pmi=datai;void CSudoku:display()printf(n);for(int i=0;i9;+i)for(int j=0;j0)if(j%3=0)printf( %d,mapij);elseprintf( %d,mapij);elseif(j%3=0)printf( );elseprintf( );printf(n);i
12、f (i!=8)if(i+1)%3=0)printf(n);elseprintf(n); printf(n);int CSudoku:resolve(int mod)smod=mod;if(mod=ALL)solves=0;dfs();return solves;else if(mod=ANY)trydfs();return 0;catch(int)return 1;return 0;int CSudoku:check(int y,int x,int *mark)int i,j,is,js,count=0;for(i=1;i=9;+i)marki=0;for(i=0;i9;+i)markmap
13、yi=1;for(i=0;i9;+i)markmapix=1;is=y/3*3;js=x/3*3;for(i=0;i3;+i)for(j=0;j3;+j)markmapis+ijs+j=1;for(i=1;i=9;+i)if(marki=0)count+;return count;void CSudoku:dfs()int i,j,im=-1,jm,min=10;int mark10;/ display();/求自由度最小的格mapimjmfor(i=0;i9;+i)for(j=0;j9;+j)if(mapij) /如果此格已填入数则看一下格。continue;int c=check(i,j,
14、mark); /如果此格空,则求其自由度。if(c=0) /已到结尾,没有空格了。 return;if(cmin)im=i;jm=j;min=c;if(im=-1) /若im=-1,则格子都填满。if(smod=ALL) /smod=ALL是求解过程。/printf(No. %d:n,+solves);display(); return; else if(smod=ANY) /smod=ANY是初始化过程。throw(1);check(im,jm,mark);for(i=1;i=9;+i)if(marki=0)mapimjm=i; /从小到大让第一个可填的数填入自由度最小的格。dfs();ma
15、pimjm=0; return;void CSudoku:analyze()while(1)cout % endl;cout % 请问你想做什么? % endl;cout %=% endl;cout % % endl;cout % 1. 查找最小不确定度的格子 % endl;cout % 2. 指定格子的可填数 % endl;cout % 3. 给指定格子填数 % endl;cout % 4. 显示当前数独 % endl;cout % 5. 查看结果 % endl;cout % 6. 返 回 % endl;cout % % endl;cout % select;switch(select)ca
16、se 1: /求不确定度最小的空格mapimjmint i,j,im=-1,jm,min=10;int mark10;for(i=0;i9;+i)for(j=0;j9;+j)if(mapij) /如果此格已填入数则看一下格。continue;int c=check(i,j,mark); /如果此格空,则求其不确定度。if(c=0)cout不能得到结果或已无空格子!自动返回! endl;return;if(cmin)im=i;jm=j;min=c;coutendl不确定度最小的格子为: im,jm 其可填的数的个数为: minendlendl;coutpress enter to continu
17、e! endl;getchar();getchar();break;case 2:int x,y;int mark10;coutendlxy;getchar();while (mapxy!=0)coutendl警告: 此格已经有数!请重新输入.endlendl;coutxy;getchar();int i,j,is,js,count=0;for(i=1;i=9;+i)marki=0;for(i=0;i9;+i)markmapxi=1;for(i=0;i9;+i)markmapiy=1;is=x/3*3;js=y/3*3;for(i=0;i3;+i)for(j=0;j3;+j)markmapis
18、+ijs+j=1;coutendl此格可填数为:;for(i=1;i=9;+i)if(marki=0)count+;coutsetw(4)i;coutendl;coutpress enter to continue! endl;getchar();break;case 3:int x,y;coutendlxy;coutmapxy;cout您填入的格为: mapx,y=mapxyendl;coutpress enter to continue! endl;getchar();getchar();break;case 4:coutendl当前随机数独: endl; display();coutpr
19、ess enter to continue! endl;getchar();getchar();break;case 5:coutendl显示结果: endl;resolve(); /没有输入参数,则默认为smod=ALL,见程序开始函数声明。coutpress enter to continue! endlendl;getchar();getchar();break;case 6:return;default:cout输入错误,请重新输入.endl;break;void main()int blanks;while(1)bool exit_f=true;coutendl;cout % end
20、l;cout % SUDOKU游戏 % endl;cout % 任二艳制作 % endl;cout %=% endl;cout % 1. 新游戏 % endl;cout % 2. 退 出 % endl;cout % select;switch (select)case 1: /开始新游戏while(exit_f)cout % endl;cout % 请选择游戏难度 % endl;cout %=% endl;cout % % endl;cout % 1. 简 单 % endl;cout % 2. 中 等 % endl;cout % 3. 困 难 % endl;cout % 4. 返 回 % endl;cout % % endl;cout % endl;/* coutendl请选择游戏难度: endl;cout= endl;cout1. 简 单endl;cout2. 中 等endl;cout3. 困 难endl;cout4. 解一个已知数独 endl;cout5. 退 出
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1