埃及分数

Problem:

在古埃及,人们使用单位分数的和(形如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
第一行:N 表示有N组测试数据,每组测试数据为一行包含a,b(0〈a〈b〈1000)。 

Output
每组测试数据若干个数,自小到大排列,依次是单位分数的分母。 

Sample Input
1
19 45

Sample Output
5 6 18

程序代码实现:

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iomanip>
using namespace std;

const double zero=1e-20;
const double maxn=1e20;

int num;
bool bb;
double tempa[1000],tempb[1000],best[1000],v[1000];

int g_cd(int a,int b)
{
    int ta,tb;
    ta=a;tb=b;
    if(ta<tb)swap(ta,tb);
    if(!(ta%tb))return tb;
    else return g_cd(tb,ta%tb);
}

void solve(int x)
{
    int i,next,temp,prev;
    if(x>num)
    {
        if(fabs(tempa[num])<zero)
        {
                bb=1;
                if(v[num]<best[num])
                 for(i=1;i<=num;i++)
                    best[i]=v[i];
        }
    }else
    {
        prev=(int(tempb[x-1]/tempa[x-1])>int(v[x-1]+1))?int(tempb[x-1]/tempa[x-1]):int(v[x-1]+1);
        next=int((num-x+1)*tempb[x-1]/tempa[x-1]+zero);
        if(tempb[x-1]/tempa[x-1]+num-x+1>best[num])return;
        for(i=prev;i<=next;i++)
        {
            v[x]=i;
            tempa[x]=tempa[x-1]*i-tempb[x-1];
            if(tempa[x]<0)continue;
            tempb[x]=tempb[x-1]*i;
            if(tempa[x]>-zero && int(tempa[x]*v[x]/tempb[x])<=num-x)
              solve(x+1);
        }
    }
}

int main(int argc, char *argv[])
{
    int i,j,n,temp,a,b;
    cin>>n;
    for(j=0;j<n;j++)
    {
        cin>>a>>b;
        cout<<a<<"/"<<b<<"=";
        temp=g_cd(a,b);
        a/=temp;b/=temp;
        if(a==1)
              cout<<a<<"/"<<b<<"="<<endl;
        else
        {
                v[0]=b/a;num=1;
                bb=0;best[1]=maxn;
                while(1)
                {
                    num++;
                    best[num]=maxn;
                    tempa[0]=a;tempb[0]=b;
                    solve(1);
                    if(bb)break;
                }
                for(i=1;i<num;i++)
                    cout<<setiosflags(ios::fixed)<<setprecision(0)<<"1/"<<best[i]<<'+';
                cout<<"1/"<<best[num]<<endl; 
        }
    }
    system("PAUSE");    
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值