使用三个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或者等很久。