迭代加深搜索--埃及分数

来源:互联网 发布:mac有安卓模拟器 编辑:程序博客网 时间:2024/05/29 10:54

 需要用单位分数1/a表示任意分数,并且加数中不能有相同的,加数少的比加数多的好,个数相同时,最小的分数越大越好。

首先,加数的个数不确定,bfs的话,从第一个比a/b小的数1/c开始,可能从所有比它小的数开始加,一层都遍历不完。

dfs,如果直接从1/c开始,找到答案可能很慢,对于加数个数和大小的限制实现起来很慢。


迭代加深搜索:从小到大枚举深度上限maxd,每次执行只考虑深度不超过maxd的结点

对于可以用回溯法求解但是解答树的深度没有明显上界的题目,可以考虑迭代加深搜素。

若设深度上限为maxd,当前结点n的深度为g(n),乐观估价函数为h(n),则当g(n) + h(n) > maxd时应该剪枝,就成为IDA*算法。

h(n)剪枝,按分母递增的顺序来扩展,扩展到第i层,前i个分数的和为c/d,第i个分数为1/e,接下来至少需要(a/b - c/d)/(1/e)个分数。



#include <iostream>

#include <cstring>

#include <cstdio>

using namespace std;

const int maxn = 1000 + 5;

typedef long long ll;

ll ans[maxn],v[maxn];//v为暂时存放

int maxd = 0;


ll gcd(ll a,ll b)

{

    if(b == 0return a;

    return gcd(b, a % b);

}

ll get_first(ll a,ll b)

{

    ll c = b / a;

    if (c * a >= b) {

        return c;

    }

    else return ++c;

}

bool better(int d)//如果vans好,返回true

{

    for (int i = d; i >= 0; i --) {

        if (v[i] != ans[i]) {

            return ans[i] == -1 || v[i] < ans[i];//d层第一次找到之前,ans[d] 值为-1

        }

    }

    return false;

}

bool dfs(int d,ll from,ll aa,ll bb)//深度为d时,还需要凑aa/bb

{

    if (d == maxd) {

        if (bb % aa) {

            return false;

        }

        else v[d] = bb / aa;

        if(better(d)) memcpy(ansvsizeof(ll) * (d + 1));//

        return true;

    }

    bool ok = false;

    from = max(from,get_first(aa, bb));

    for (ll i = from; ; i ++) {

        if(bb * (maxd - d + 1) <= i * aa) break;//剪枝

        v[d] = i;

        ll a2 = aa * i - bb;

        ll b2 = bb * i;

        ll g = gcd(a2,b2);

        if (dfs(d + 1, i + 1, a2 / g, b2 / g)) ok = true;

    }

    return ok;

}

int main()

{

    ll a,b;

    cin >> a >> b;

       int ok = 0;

    for (maxd = 1; ; maxd ++) {

        memset(ans, -1sizeof(ans));

        if(dfs(0,get_first(a,b),a,b)){ok = 1;break;}

    }

    for (int i = 0; i < maxd; i ++) {

        printf("%lld ",ans[i]);

    }

    printf("%lld\n",ans[maxd]);

    return 0;

}