codevs 1288 埃及分数

时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
题目描述 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

数据范围及提示 Data Size & Hint
 
 
迭代加深+剪枝
#include <cstring>
#include <cstdio>
typedef long long LL;
const LL inf = 2147483647;
bool flag;
LL a,b,len,ans[100],ls[100];
inline LL max(LL a,LL b) {return a>b?a:b;} 
LL gcd(LL m,LL n) {return !n?m:gcd(n,m%n);}
void dfs(LL now,LL from,LL m,LL n)
{
    if(now>len) return; 
    if(m==1&&n>ls[now-1])
    {
        ls[now]=n;
        if(!flag||ls[now]<ans[now])
        {
            for(LL i=1;i<=now;++i) ans[i]=ls[i];
        }
        flag=1;
        return;
    }
    from=max(from,n/m+1);
    for(LL i=from;;++i)
    {
        if(n*(len-now+1)<=m*i) break;
        ls[now]=i;
        LL Gcd=gcd(i*m-n,i*n);
        dfs(now+1,i+1,(i*m-n)/Gcd,(i*n)/Gcd);
    }
}
int main()
{
    scanf("%lld%lld",&a,&b);
    LL Gcd=gcd(a,b);
    a/=Gcd,b/=Gcd; 
    flag=false;
    ls[0]=1;
    for(len=1;;++len)
    {
        dfs(1,b/a+1,a,b);
        if(flag) break;
    }
    for(LL i=1;i<=len;++i) i==len?printf("%lld\n",ans[i]):printf("%lld ",ans[i]);
    return 0;
}

 

posted @ 2017-09-13 15:11  杀猪状元  阅读(167)  评论(0编辑  收藏  举报