数独问题--解题思路描述:
解题思路描述:
数独游戏,对于我们并不陌生,在意林和读者期刊的尾页不时会有刊登,所以规则是了解的:9*9网格,同时分成9个九宫格,有固定数字,而我们的任务是将剩余无数字部分填满,达到每一行,每一列,每一个九宫格都没有相同数字的要求。
首先第一个任务是生成数独终局:解决的方法有两种。
第一种方法:在排列之中,会发现有一种典型的矩阵组合刚好满足数独规则的要求:
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
7 |
8 |
9 |
1 |
2 |
3 |
4 |
5 |
6 |
4 |
5 |
6 |
7 |
8 |
9 |
1 |
2 |
3 |
9 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
6 |
7 |
8 |
9 |
1 |
2 |
3 |
4 |
5 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
1 |
2 |
8 |
9 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
5 |
6 |
7 |
8 |
9 |
1 |
2 |
3 |
4 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
1 |
这个数独由第一行的1~9的全排列决定,也就是说,全排列有多少种,这种典型数独就有多少种,而由9!= 362880。因为第一个数字的要求,这种典型数独也就只能带来8!= 40320的数独终局,离项目的1000000个数独终局还差将近25倍。
而在观察中得到,交换4~6行和7~9行中的任意两行,都可以得到一个新的符合要求的数独终局,这样子我们就可以在原来的基础上得到6*6=36倍的数独终局,符合了项目中的要求。具体代码实现如下:
void makesudo(int list[9]){
int lists[9];
char lis[600];
int bi = 0;
for (int i = 0; i < 9; i++){
for (int j = 0; j < mov[i]; j++){
lists[mov[i] - 1 - j] = list[8 - j];
}
for (int j = 0; j < 9 - mov[i]; j++){
lists[j + mov[i]] = list[j];
}
for (int j = 0; j < 9; j++){
if (j == 0) lis[bi++] = lists[j] + '0';
else{
lis[bi++] = ' ';
lis[bi++] = lists[j] + '0';
}
}
lis[bi++] = '\n';
}
lis[bi++] = '\n';
lis[bi] = '\0';
nown++;
fputs(lis, fp);
if (nown == n){
return;
}
}
void makemov(int list[9]){
mov[0] = 0;
for (int i = 0; i < 2; i++){
for (int j = 0; j < 6; j++){
for (int k = 0; k < 6; k++){
for (int a = 0; a < 2; a++){
mov[1+a] = er1[i][a];
}
for (int a = 0; a < 3; a++){
mov[3+a] = er2[chan[j][a]];
}
for (int a = 0; a < 3; a++){
mov[6+a] = er3[chan[k][a]];
}
makesudo(list);
if (nown == n){
goto part1;
}
}
}
}
part1:return;
}
第二种方法:
我们知道,当一个数独的条件数字少于30个时,可以有多个解,而当我们进行设计时可以通过解数独的形式直接生成数独终局,设计20个无关条件数字,运行接下来的求解函数即可。
求解函数会于下次更新给出。