codevs 1288 埃及分数

时间限制: 1 s
空间限制: 128000 KB
题目描述 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 Description

a b

输出描述 Output Description

若干个数,自小到大排列,依次是单位分数的分母。

样例输入 Sample Input

19 45

样例输出 Sample Output

5 6 18


【分析】
题目好理解,做起来如同日狗。
第一道迭代加深搜索。
根据题目要求:加数越少越好,所以用迭代加深。
具体解释程序中有注释哒。


【代码】

//codevs 1288 埃及分数
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long 
#define mxn 2147483647
#define fo(i,j,k) for(long long i=j;i<=k;i++)
using namespace std;
int k;
ll a,b;
bool czy;
ll ans[20],v[20];
inline ll gcd(ll x,ll y)  //以下两个函数不用多解释 
{
    if(x%y==0) return y;
    return gcd(y,x%y);
}
inline bool yue(ll x,ll y)
{
    ll c=gcd(y,x);
    x=x/c,y=y/c;
    if(x==1) return 1;
    return 0;
}
inline void dfs(int dep,ll aa,ll bb)
{
    if(dep==k)  //满足层数后进行判断 
    {
        if(bb%aa!=0) return;
        v[k]=bb/aa;
        if(v[k]!=v[k-1] && v[k]<ans[k])
        {
            fo(i,1,k) ans[i]=v[i];
            czy=1;
        }
        return;
    }
    ll low=max(v[dep-1]+1,bb/aa);  //下界满足两个条件:比上一个大且不超过当前数字。 
    ll high=bb*(k-dep+1)/aa;   //上界条件:如果剩下所有分数都是这个数,能凑齐当前数字 
    if(high>mxn) high=mxn;     //不要超过int范围,要不太浮夸 
    if(k && bb/aa+k-dep+1>=ans[k]) return;  //如果最后的最优数字比当前最优解大,跳出
    fo(i,low,high)
    {
        v[dep]=i;
        ll fi=aa*i-bb,se=bb*i;  //这步是计算当前数字-1/i后所得到的答案
        if(fi<=0 || se<=0) continue;  //防止出现玄学RE问题 
        yue(fi,se);
        dfs(dep+1,fi,se);
    } 
}
int main()
{
    scanf("%lld%lld",&a,&b);
    if(yue(a,b))
    {
        printf("%lld\n",b);
        return 0;
    }
    for(k=2;k<=13;k++)
    {
        memset(ans,0x3f,sizeof ans);
        v[0]=0;
        dfs(1,a,b);
        if(czy)
        {
            fo(i,1,k) printf("%lld ",ans[i]);
            printf("\n");
            return 0;
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值