UVa 12558 Egyptian Fractions (HARD version)--迭代加深搜索

题目链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=842&page=show_problem&problem=4003
题目大意:
把一个真分数表示成一系列埃及分数的和,要求项数最少,且最小分数值最大以此类推。并且给出 k(5) 个数,不能选用
分析:
对于这种没有搜索上限的题最好采用迭代加深搜索,设置一个上限 maxd ,
上限 maxd 还可以用来剪枝,当扩展到第 i 层时,若剩余值为 d/c ,接下来要考虑的分数为 1/e 则至少应该满足 1/e(maxd+1d)d/c ,反之则会被剪枝。

wrong了很多次才发现bug的代码。。
最初的bug:考虑最后一个值即 b/a 时未考虑 b/a 是否在给出的K个数内

#include 
#include
#include
#include
#include
#define MAXN 100000

using namespace std;

typedef long long  LL;

LL v[MAXN],ans[MAXN];
LL maxd;

LL a ,b,k,K[10];
LL gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}

bool better(LL d)
{
    for(LL i=d ; i>-1; --i)
        if(v[i]!=ans[i])return ans[i] == -1||v[i]bool dfs(LL d,LL from,LL a,LL b)
{
    if(d == maxd)
    {
        if(b%a)return false;
        bool fk = false;
        if(b/a<=1000)
        {
            for(int j = 0 ; jif(K[j] == b/a)
            {
                fk = true;
                break;
            }
        }
        if(fk)return false;
        v[d] = b/a;
        if(better(d))memcpy(ans,v,sizeof(LL)*(d+1));
        return true;
    }
    from = max(from,b/a+1);
    bool ok = false;

    for(LL i = from ; ;i++)
    {
        bool fk  = false;
        if(b*(maxd+1-d)<=a*i)break;
        if(i<=1000)
        {
            for(int j = 0 ; jif(K[j] == i)
            {
                fk = true;
                break;
            }
        }
        if(fk)continue;
        //i合法,计算剩余分数
        v[d] = i;
        LL bb = b*i;
        LL aa = a*i-b;
        LL g = gcd(aa,bb);

        if(dfs(d+1,i+1,aa/g,bb/g)){ok = true;}
    }
    return ok;
}


int main()
{
  //freopen("H:\\c++\\file\\stdin.txt","r",stdin);
    int T;
    scanf("%d",&T);
    int kase = 0;


    while(T--)
    {
        scanf("%lld %lld %lld",&a,&b,&k);
        for(int i=0 ; iscanf("%lld",&K[i]);

        for(maxd = 1 ; ;++maxd)
        {
            memset(ans,-1,sizeof(ans));
            if(dfs(0,b/a+1,a,b)){break;}
        }
        printf("Case %d: ",++kase);
        printf("%lld/%lld=",a,b);
        for(int i=0 ; iprintf("1/%lld+",ans[i]);
        printf("1/%lld",ans[maxd]);

        putchar('\n');
    }
    return 0;

}

你可能感兴趣的:(算法刷题)