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