145 lines
4.3 KiB
Markdown
145 lines
4.3 KiB
Markdown
|
|
### 一、题目大意
|
|||
|
|
昨日,糖豆做了一道小学四年级数学举一反三试题:
|
|||
|
|
|
|||
|
|
$\large ~~~~abcdef$
|
|||
|
|
$\large + abcdef$
|
|||
|
|
$\large ----$
|
|||
|
|
$\large ~~~jeghba$
|
|||
|
|
|
|||
|
|
已知题目中所有字符是非负整数,求$abcdef$和$jeghba$的值是多少?
|
|||
|
|
|
|||
|
|
此题我给出的数学方法是画树形图,标注分支,然后尝试每个分支,判断是否符合题目,是否可以剪枝,但计算量很大,糖豆历时$20$分钟,完成此题。
|
|||
|
|
|
|||
|
|
回头思考,既然都画了树形图,不如使用编程的办法尝试一下,随即做了两套办法,现整理给同学们参考,望大家深入理解深搜的优势,以及它的实现细节。
|
|||
|
|
|
|||
|
|
### 二、循环暴力法
|
|||
|
|
|
|||
|
|
$Running~time:1000ms$
|
|||
|
|
$1$秒内完成计算,无法优化了,没法剪枝。贵在思路简单,好上手。
|
|||
|
|
```c++
|
|||
|
|
#include <bits/stdc++.h>
|
|||
|
|
|
|||
|
|
using namespace std;
|
|||
|
|
|
|||
|
|
const int N = 10;
|
|||
|
|
int a[N], al; //用于将最终的两个原数字相加的结果 拆分到数组中
|
|||
|
|
int b[N], bl; //用于拆分原数字到数组中
|
|||
|
|
|
|||
|
|
int main() {
|
|||
|
|
//记录开始时间
|
|||
|
|
clock_t begin = clock();
|
|||
|
|
|
|||
|
|
// 1234
|
|||
|
|
//排重后数字个数
|
|||
|
|
unordered_set<int> _set1, _set2;
|
|||
|
|
|
|||
|
|
for (int i = 123456; i < 1000000 / 2; i++) {
|
|||
|
|
int x = i;
|
|||
|
|
int y = i + i;
|
|||
|
|
|
|||
|
|
al = 0;
|
|||
|
|
while (y) a[++al] = y % 10, y /= 10;
|
|||
|
|
|
|||
|
|
bl = 0;
|
|||
|
|
while (x) b[++bl] = x % 10, x /= 10;
|
|||
|
|
|
|||
|
|
_set1.clear();
|
|||
|
|
for (int j = 1; j <= al; j++) _set1.insert(a[j]);
|
|||
|
|
if (_set1.size() != 6) continue;
|
|||
|
|
|
|||
|
|
_set2.clear();
|
|||
|
|
for (int j = 1; j <= bl; j++) _set2.insert(b[j]);
|
|||
|
|
if (_set2.size() != 6) continue;
|
|||
|
|
|
|||
|
|
if (a[1] == b[6] && a[2] == b[5] && a[5] == b[2]
|
|||
|
|
&& !_set2.count(a[3]) && !_set2.count(a[4]) && !_set2.count(a[6]))
|
|||
|
|
printf("%d\n", i);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//记录结束时间
|
|||
|
|
clock_t end = clock();
|
|||
|
|
cout << "Running time:" << (double)(end - begin) / CLOCKS_PER_SEC * 1000 << "ms" << endl;
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 三、深搜+剪枝
|
|||
|
|
$Running~~ time:3ms$
|
|||
|
|
|
|||
|
|
逆天的$3ms$!整整快了$300$倍~
|
|||
|
|
|
|||
|
|
<font color='red' size=4><b>分析:
|
|||
|
|
因深搜可以在行进过程中随时发现问题,随时终止此分支前进,防止了很多无用的枚举。
|
|||
|
|
</b></font>
|
|||
|
|
|
|||
|
|
```c++
|
|||
|
|
#include <bits/stdc++.h>
|
|||
|
|
|
|||
|
|
using namespace std;
|
|||
|
|
/*
|
|||
|
|
|
|||
|
|
输出:
|
|||
|
|
468532
|
|||
|
|
*/
|
|||
|
|
const int N = 10;
|
|||
|
|
int num; //不断增加的前缀,最终是选择的数字
|
|||
|
|
bool st[N]; // 0~9哪个数字使用过
|
|||
|
|
int a[N], al; //用于将最终的两个原数字相加的结果 拆分到数组中
|
|||
|
|
int b[N], bl; //用于拆分原数字到数组中
|
|||
|
|
|
|||
|
|
void dfs(int u) {
|
|||
|
|
if (u == 7) { //完成所有数位的枚举
|
|||
|
|
int sum = num << 1, tmp = num;
|
|||
|
|
|
|||
|
|
//拆分到数组中
|
|||
|
|
al = 0;
|
|||
|
|
while (sum) a[++al] = sum % 10, sum /= 10;
|
|||
|
|
|
|||
|
|
bl = 0;
|
|||
|
|
while (tmp) b[++bl] = tmp % 10, tmp /= 10;
|
|||
|
|
|
|||
|
|
//判断条件,能剪枝的代码,尽量提前,减少后面无用的计算
|
|||
|
|
// 放在unordered_set前面,可以做到: Running time:3ms
|
|||
|
|
if (a[1] != b[6] || a[2] != b[5] || a[5] != b[2]) return;
|
|||
|
|
if (st[a[6]] || st[a[4]] || st[a[3]]) return;
|
|||
|
|
|
|||
|
|
// Running time:526ms
|
|||
|
|
//判断是不是结果存在数位值重复
|
|||
|
|
unordered_set<int> _set;
|
|||
|
|
for (int i = 1; i <= al; i++) _set.insert(a[i]);
|
|||
|
|
if (_set.size() < 6) return;
|
|||
|
|
|
|||
|
|
//全部符合要求,输出结果
|
|||
|
|
printf("%d\n", num);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
for (int i = 0; i <= 9; i++) {
|
|||
|
|
//首位不能达到5,否则就是7位了,剪枝
|
|||
|
|
//如果是首位,a!=1,因为加法的结果个数是1,加法结果最小应该是2开始
|
|||
|
|
// a只能是2,4
|
|||
|
|
if (u == 1 && (i != 2 && i != 4)) continue;
|
|||
|
|
if (!st[i]) {
|
|||
|
|
st[i] = true;
|
|||
|
|
num = num * 10 + i; //增加上此位
|
|||
|
|
dfs(u + 1); //下一个位置
|
|||
|
|
// num = (num - i) / 10; //减回去此位
|
|||
|
|
//简写
|
|||
|
|
num = num / 10; //减回去此位
|
|||
|
|
st[i] = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
int main() {
|
|||
|
|
//记录开始时间
|
|||
|
|
clock_t begin = clock();
|
|||
|
|
|
|||
|
|
dfs(1);
|
|||
|
|
|
|||
|
|
//记录结束时间
|
|||
|
|
clock_t end = clock();
|
|||
|
|
cout << "Running time:" << (double)(end - begin) / CLOCKS_PER_SEC * 1000 << "ms" << endl;
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
```
|