最近寫了好幾道DFS相關的題目,想起以前玩過的一個遊戲:數獨,因爲都是一個類型的思想,所以很快就想到了用 DFS來求解 數獨,此文章來教你一步一步來實現一個數獨模擬器 . . .
.
相關文章:
藍橋杯DFS經典題 —— 算式900、 寒假作業(告別枚舉法)
我們需要求解的數獨就是世界上最難的數獨:
這個數獨被當時一個 69歲的爺爺花了三天時間給算出了,有這樣一個故事:
下面我將帶大家手把手寫出這樣的一個小程序,來快速的求解出世上最難的數獨 . . .
首先,我們都知道數獨是有規則的,上面的數據不是隨便放的,規則如下:
- 一行九個數據,9個數字必須出現
- 一列九個數據,9個數字必須出現
- 一個九宮格,9個數字必須出現
比如下面這個情況纔是允許存在的:
所以,我們需要寫一個方法,用來判斷當前的這個數字是否允許存放在這個數獨之中,代碼如下:
bool JudgeIsNoWant(int n) // n 表示是當前的第幾個數
{
int x = n / 9; // 定位當前數的位置(數據在二維數組中的位置)
int y = n % 9;
for (size_t i = 0; i < 9; i++) // 橫豎 搜索
{
if (arr[x][i] == arr[x][y] && i != y) return false;
if (arr[i][y] == arr[x][y] && i != x) return false;
}
// 九宮格 搜索 這裏需要一個小小的算法,確定九宮格的位置
for (size_t i = x / 3 * 3; i < x / 3 * 3 + 3; i++)
for (size_t j = y / 3 * 3; j < y / 3 * 3 + 3; j++)
if (arr[i][j] == arr[x][y] && (i != x || j != y))
return false;
return true;
}
其中的九宮格位置確定算法如下所示:
其中,這個 X 的值的位置是 (4,5),九宮格起始位置是(3,3),我們需要設計一個算法來打出這個點,而這個算法就是上面代碼上所述的:
- 4 / 3 * 3 = 3
- 5 / 3 * 3 = 3
.
下面我們就可以使用 DFS 來求解這個世上最難的數獨了,代碼如下所示:
void Dfs(int n) // 深搜思想
{
// 判斷上一個數據是否滿足條件( 橫、豎、九宮格 )
if (n > 0 && n <= 81) if (!JudgeIsNoWant(n - 1)) return;
if (n >= 81) // 到最後則輸出數據並且返回
{
cout << endl << endl << "解爲:" << endl << endl;
for (size_t i = 0; i < 9; i++){
for (size_t j = 0; j < 9; j++)
{
cout << arr[i][j] << " ";
if (j % 3 == 2) cout << " ";
}
cout << endl;
if (i % 3 == 2) cout << endl;
}
return;
}
int x = n / 9; // 定位當前數的位置
int y = n % 9;
if (arr[x][y] != 0) // 只對 數字爲 0 的元素進行搜索
Dfs(n + 1);
else {
// 每一個空位有 10 種可能性
for (size_t i = 1; i < 10; i++) {
arr[x][y] = i; // 當前的數字放入到數組之中,
Dfs(n + 1); // 進行下一個位置的搜索
arr[x][y] = 0; // 不滿足條件,重新清 0
}
}
}
這裏的關鍵點在於這一行代碼:
爲什麼我們需要判斷上一個數字是否滿足條件呢?而不是當數組中有了新的數據就直接判斷呢?
如果是後一種思想求解將造成很多的問題,且非常不方便,之前試過沒有成功 . . .
~
測試代碼就是讀取一個數獨,然後調用我們的 DFS方法(從 0開始):
/*
世界上最難的數獨:
0 0 5 3 0 0 0 0 0
8 0 0 0 0 0 0 2 0
0 7 0 0 1 0 5 0 0
4 0 0 0 0 5 3 0 0
0 1 0 0 7 0 0 0 6
0 0 3 2 0 0 0 8 0
0 6 0 5 0 0 0 0 9
0 0 4 0 0 0 0 3 0
0 0 0 0 0 9 7 0 0
*/
cout << "請輸入需要求解的數獨:" << endl << endl;
for (size_t i = 0; i < 9; i++)
for (size_t j = 0; j < 9; j++)
cin >> arr[i][j];
Dfs(0); // 從第一個開始測試
這個世界上最難的解爲:
我們可以用如下的方式來測試一下這個 DFS 用了多少 ms :
通過大量的測試後,我們發現要想求出這個解就要花費 80ms 左右的時間 . . .