DFS迭代加深
在做题中我们经常会遇到用BFS存不下状态,DFS又容易挂的情况,这个时候我们可以考虑把它们两者的优点结合起来。
BFS常用于找最优解,缺点是需要存下所有状态;而DFS所需空间小,但有可能会“误入歧途”浪费很多时间。比如这个:
迭代加深简单来说就是每次限定搜索的深度,如果搜索到了限定深度就return;
int maxdep;
for (maxdep = 1; maxdep <= 最大深度;maxdep++) {
dfs();
……
}
这样一来上面那个例子就会快很多:
例题(入门OJ1261):
埃及分数
Description
在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数。
如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的。
对于一个分数a/b,表示方法有很多种,但是哪种最好呢?
首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。
如:
19/45=1/3 + 1/12 + 1/180
19/45=1/3 + 1/15 + 1/45
19/45=1/3 + 1/18 + 1/30,
19/45=1/4 + 1/6 + 1/180
19/45=1/5 + 1/6 + 1/18.
最好的是最后一种,因为1/18比1/180,1/45,1/30,1/180都大。
给出a,b(0〈a〈b〈1000),编程计算最好的表达方式。
Input
一行包含a,b(0〈a〈b〈1000)。
Output
每组测试数据若干个数,自小到大排列,依次是单位分数的分母。
Sample Input
19 45
Sample Output
5 6 18
分析:
这个题是 1260 的升级加变化版,仔细看看不难发现如果BFS空间不够,DFS的话又太慢,所以考虑使用迭代加深优化
代码如下:
#include
#define ll long long
using namespace std;
ll a, b;
ll maxdep;
ll fm[1000010], ans[1000010];
//快读
inline ll read() {
ll x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
//最大公约数
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll get_max(ll a, ll b) {for (ll i = 2; ; i++) if (a * i > b) return i;}
bool dfs(ll a, ll b, ll dep) {
bool flag = 0;
if (dep == maxdep) {
if (b % a) return 0;
fm[dep] = b / a;
if (fm[dep] < ans[dep] || ans[0] == 0) {
memcpy(ans, fm, sizeof fm);
}
return 1;
}
for (ll i = get_max(a, b); ; i++) {
if ((maxdep - dep + 1) * b <= a * i) break;
fm[dep] = i;
ll d = gcd(a * i - b, b * i);
if (dfs((a * i - b) / d, (b * i) / d, dep + 1)) flag = 1;
}
return flag;
}
int main() {
a = read(), b = read();
for (maxdep = 1; ; maxdep++) {//迭代加深
memset(fm, 0, sizeof fm);
memset(ans, 0, sizeof ans);//初始化
if (dfs(a, b, 0)) {
for (ll i = 0; i <= maxdep; i++) {
if (i == 0) printf("%lld", ans[i]);
else printf(" %lld", ans[i]);
}
return 0;
}
}
}
好像又叫分支限界来着:)
(逃