使用三个flag作为判断数独是否满足数独性质。
flag1:row[10][9],其中row[0][*]不使用。row[n][x]它代表的意思是,数字n在第x行是否出现过。
flag2:column[10][9],其中column[0][*]不使用。column[n][y]它代表的意思是,数字n在第y列是否出现过。
flag3:cell[10][9],其中cell[0][*]不使用。cell[n][k]它代表的意思是,数字n在第k个小小宫格(我的是这样标记:从左到右,从上到下)是否出现过。
dfs的参数有x,y。代表现在填的数字是在x,y位置。
dfs伪代码原理:
1. 如果全部填完,那么该数独的这种填法就是其中一种解,输出该数独解。
2.如果还没填完,填到了第x,y位置,判断该位置是否有数字(原题该位置有就有,没有就没有),如果有,填下一个位置。
如果没有,寻找1-9数字在三个flag中为0的数字。找到了,标记flag(3个)为1,填下一个位置。
3.回溯法是恢复之前的flag和数据,即恢复为0,因此,每次填完数字,即在尝试该数据填完后,恢复flag和原来的数独数字
c++的代码如下:
// shudu.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"//你可能需要删除掉这个
#include <iostream>
using namespace std;
int row[10][9];
int column[10][9];
int cell[10][9];
int data1[9][9];
/*
初始标记
*/
void init() {
for (int i = 1; i < 10; i++) {
for (int j = 0; j < 9; j++) {
data1[i-1][j]=row[i][j] = column[i][j] = cell[i][j] = 0;
}
}
}
/*
显示数独
*/
void showShudu() {
cout << "The result:" << endl;
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (j != 0) cout << " ";
cout << data1[i][j];
}
cout << endl;
}
cout << "-----------------" << endl;
}
int count1 = 0;
/*
dfs暴力求解
*/
void solve(int x,int y) {
if (x >= 9) {
count1++;
showShudu();
cin.get();
return;
}
int nextY = (y + 1) % 9;
int nextX = x + (y + 1) / 9;
if (data1[x][y] != 0) {
solve(nextX, nextY);
return;
}
for (int i = 1; i < 10; i++) {
if (row[i][x]) continue;
if (column[i][y]) continue;
if (cell[i][x / 3 * 3 + y / 3]) continue;
row[i][x] = column[i][y] = cell[i][x / 3 * 3 + y / 3] = 1;
data1[x][y] = i;
solve(nextX,nextY);
row[i][x] = column[i][y] = cell[i][x / 3 * 3 + y / 3] = 0;//回溯法,只能放在这里咯
}
data1[x][y] = 0;//这也是回溯法,没有这个不行,但为什么可以放在这里?当然也可以放在上面循环里面去
//放在这里可以减少计算量喽
}
/*
读取数独题目,从filename文件读取
*/
void setShudu(const char *filename) {
FILE *fp = fopen(filename, "r");
int * dataP = *data1;//看不懂???
for (int i = 0; i < 81; i++) fscanf(fp, "%d",dataP++);
fclose(fp);
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (data1[i][j] != 0) {
row[data1[i][j]][i] = 1;
column[data1[i][j]][j] = 1;
cell[data1[i][j]][i / 3 * 3 + j / 3] = 1;
}
}
}
}
void startShudu() {
init();
setShudu("1.txt");//数独题目放在1.txt里面(有81个数字0-9,其中0代表未填)
solve(0, 0);//从位置0,0开始
}
int main()
{
startShudu();
return 0;
}
文本1.txt测试样例:
3 0 2 7 5 6 4 1 8
0 0 8 0 0 0 0 0 6
0 0 7 0 4 1 2 0 3
5 0 6 0 3 9 7 0 2
1 0 9 0 7 8 6 0 5
0 0 4 0 0 0 0 0 1
2 0 3 5 8 4 1 6 9
9 0 0 0 0 0 0 0 0
0 0 0 9 0 7 3 5 4
结果如下:

基本秒出结果。
这里我的代码有些漏洞,没有在读取数独数据时检测是否合法数独(正常来说,你也不会随便拿81个数字测试吧。。。)
如果你输入一开始就是个非法数独,解出很可能是error或者等很久。
本文介绍了一种基于深度优先搜索(DFS)的数独求解算法。通过使用三个标志数组来跟踪行、列和宫格内数字的出现情况,确保数独的每一行、每一列及每一个宫格内的数字都是唯一的。代码示例采用C++实现。

490

被折叠的 条评论
为什么被折叠?



