题目:埃及分数

题目描述﹡﹡﹡﹡﹡

在古埃及,人们使用单位分数的和(形如 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),试编程计算最好的表达方式。

输入格式

输入只有一行:a、b,表示需要表示的分数 a/b (0 < a < b < 1000)。

输出格式

一行,依次给出最好的表达方式中各个单位分数的分母(保证都在 32 位整型范围内)。

 

 

 

迭代深化,但实现起来很难,而且RQ上数据还有问题。

刚开始做的时候 函数传递的参数被我弄成浮点型,所以就game over了。

别人的题解 函数传递的是除数于被除数。

关键是剪枝。

首先下一个分母一定比上一个大,所以所有的分母必须单调递增,所以1/分母 单调递减。

若 tot 为后n 位 1/分母 的总和,则 tot/n 为后n 位 1/分母 的平均值,可知,当下的分母小于 平均值的倒数。

所以 搜索的范围就求出来了。

 

 

#include<iostream>
using namespace std;

long long a,b,g;
int l,ans[100],best[100]; 
bool p=0; 

long long gcd(long long x,long long y){
     long long z; 
     while(x!=0)
     {z=x;x=y%x;y=z;} 
     return y; 
     } 

void Dfs(long long x,long long y,int h){
     int i; 
     if(h==l) 
     {
      g=gcd(x,y);
      x/=g;y/=g; 
      if(x==1&&y>0&&y>ans[h-1]) 
      {
       if(p==0||(p==1&&y<best[h]))
       {
        for(i=1;i<h;++i) best[i]=ans[i];
        best[h]=y;p=1; return ;           
               }             
                  } 
      return ; 
              } 
     
     int mi=ans[h-1]+1,ma=(l-h+1)*y/x+2;
     long long xx,yy; 
     
     for(i=mi;i<=ma;++i)
     {
      ans[h]=i; 
      xx=x*i-y;yy=y*i;
      Dfs(xx,yy,h+1); 
             } 
             
     } 

int main()
{
    cin>>a>>b;
    g=gcd(a,b);
    a/=g;b/=g; 
    
    if(a==1) {cout<<b<<endl;return 0;} 
    
    for(l=2;;++l)
    {Dfs(a,b,1);if(p) break;} 
                
    for(int i=1;i<l;++i)
    cout<<best[i]<<" ";
    cout<<best[l]<<endl; 
  //  system("pause");
    return 0; 
    } 

 

 

posted on 2012-07-06 18:43  怡红公子  阅读(387)  评论(0编辑  收藏  举报