迭代加深搜索

DFS迭代加深

在做题中我们经常会遇到用BFS存不下状态,DFS又容易挂的情况,这个时候我们可以考虑把它们两者的优点结合起来。

BFS常用于找最优解,缺点是需要存下所有状态;而DFS所需空间小,但有可能会“误入歧途”浪费很多时间。比如这个:

迭代加深搜索_第1张图片

迭代加深简单来说就是每次限定搜索的深度,如果搜索到了限定深度就return;

int maxdep;
for (maxdep = 1; maxdep <= 最大深度;maxdep++) {
    dfs();
    ……
}

这样一来上面那个例子就会快很多:

迭代加深搜索_第2张图片

例题(入门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;
        }
    }
}

好像又叫分支限界来着:)

(逃

你可能感兴趣的:(搜索,搜索)