最近写了好几道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 左右的时间 . . .