类似于 算式 900、寒假作业这种题目,可以直接暴力破解,但是它非常的浪费时间,而且程序不是太过于美观,很容易让我们对算法失去兴趣,今天,我们告别传统的暴力破解,使用伟大搜索算法 —— DFS(深度优先搜索) . . .
.
DFS 相关文章如下所示:
《算法笔记》—— “迷宫求解” 之 深度优先搜索(DFS)
《算法笔记》—— 图 “邻接矩阵” 的遍历(DFS、BFS)
算式900
题目: 小明的作业本上有道思考题:
看下面的算式:
(□□□□-□□□□)*□□=900
其中的小方块代表 0~9 的数字,这10个方块刚好包含了 0 ~ 9 中的所有数字。
注意:0不能作为某个数字的首位。
小明经过几天的努力,终于做出了答案!如下:
(5012-4987)*36=900
用计算机搜索后,发现还有另外一个解,本题的任务就是:请你算出这另外的一个解。
注意:提交的格式需要与示例严格一致;
括号及运算符号不要用中文输入法;
整个算式中不能包含空格。
.
很多人看到这种类型的题目,第一想法就是暴力破解,实则没必要,但是暴力破解快乐啊! 哈哈哈,看看下面的这个代码,你还快乐吗?
代码太长我直接贴图了:
看到这个代码你真的很快乐吗? 哈哈哈 ~ 其实我非常的痛苦,感觉脑子快要裂开了 . . .(>_<)
下面我们用 DFS 来解决一下这个题目,代码如下:
#include <iostream>
using namespace std;
size_t flag[10]; // 标记 10 个数字是否被使用过
size_t arr[10]; // 存储 10 个满足题目意思的书
void Dfs(int n) // 深搜思想
{
if (n == 10) // 已经找到 10 个不重复的数
{
// 判断是否满足题目的意思 == 900
if (((arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3]) -
(arr[4] * 1000 + arr[5] * 100 + arr[6] * 10 + arr[7])) *
(arr[8] * 10 + arr[9]) == 900)
{
cout << " ( " << (arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3]) << " - " <<
(arr[4] * 1000 + arr[5] * 100 + arr[6] * 10 + arr[7]) << " ) " << " * " <<
(arr[8] * 10 + arr[9]) << " = " << 900 << endl;
}
return; // 不要忘记了这个返回
}
for (size_t i = 0; i < 10; ++i) // 每一个数都有 10 种可能
{
if (i == 0 && (n == 0 || n == 4 || n == 8)) // 个别的数只有 9 种可能 开头没有 0 的情况
continue;
if (flag[i] == 0) // 这个数字当前没有被使用过
{
flag[i] = 1; // 标记为使用过
arr[n] = i; // 将这个数存入数组之中
Dfs(n + 1); // 下一个位置的深搜
flag[i] = 0; // 这个数没有用,取消标记(便于下个位置使用)
}
}
}
int main()
{
Dfs(0);
return 0;
}
使用 DFS 是不是非常的方便呢,结果如下所示:
.
寒假作业
题目:
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
每个方块代表 1 ~ 13 中的某一个数字,但不能重复。
思想过程: 这个题目我们继续使用 DFS来求解,但我们在 DFS的过程中,会对程序进行优化,即数字个数每够一个式子成立时,判断这个式子是否满足题意,比如3 个数字时 判断 + 的那个式子,6 个 数字时判断 - 的那个式子,9 个数字时判断 * 的那个式子,12 个数字时判断 / 的那个式子 . . .
优化过程,参考度娘上的大神 ^ _ ^
.
代码如下所示:
#include <iostream>
using namespace std;
int arr[4][3];
int flag[14];
int sum;
// 判断是否满足式子的要求,优化过程
int JudgeIsNoGoOn(int n)
{
int x = n / 3;
if (n % 12 == 2) // n == 2 时,判断第一个式子是否满足条件,下面同理
{
if (arr[x][0] + arr[x][1] != arr[x][2]) return 0;
}
else if (n % 12 == 5)
{
if (arr[x][0] - arr[x][1] != arr[x][2]) return 0;
}
else if (n % 12 == 8)
{
if (arr[x][0] * arr[x][1] != arr[x][2]) return 0;
}
else if (n % 12 == 11)
{
if (arr[x][2] * arr[x][1] != arr[x][0]) return 0;
printf("%d + %d = %d\n", arr[0][0], arr[0][1], arr[0][2]);
printf("%d - %d = %d\n", arr[1][0], arr[1][1], arr[1][2]);
printf("%d * %d = %d\n", arr[2][0], arr[2][1], arr[2][2]);
printf("%d / %d = %d\n\n\n", arr[3][0], arr[3][1], arr[3][2]);
}
return 1;
}
// 与上面差不多的思想,加个判断而已 . . .
void dfs(int n)
{
int x = n / 3, y = n % 3; // 需要存储的二维数组的索引
// 到最后一个数字了,判断是否满足题目要求
if (x == 4) { if (JudgeIsNoGoOn(11) == 1) ++sum; }
else
{
for (int i = 1; i <= 13; ++i) // 每一个空位 都有 13 种可能性
{
if (flag[i] == 0)
{
flag[i] = 1;
arr[x][y] = i;
// 每存放一位数字,就判断一次(可以前几个式子就不满足)
// 当前的数字不满足条件,标记数组值还原,进行下一次的循环
if (JudgeIsNoGoOn(n) == 0)
{
flag[i] = 0;
continue;
}
dfs(n + 1); // 下一位数字继续
flag[i] = 0;
}
}
}
}
熟悉的使用 DFS 或者 BFS,可以帮我们解决很多的问题,而且也有很大的成就感,哈哈 ~
.