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 <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#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]<ans[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 ; j<k ; ++j)
                if(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 ; j<k ; ++j)
                if(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 ; i<k ; ++i)scanf("%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 ; i<maxd ; ++i)
            printf("1/%lld+",ans[i]);
        printf("1/%lld",ans[maxd]);

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

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值