數獨-dfs求解-回溯法

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章