1288 埃及分数

Posted 神犇(shenben)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1288 埃及分数相关的知识,希望对你有一定的参考价值。

 

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
 

分类标签 Tags 点此展开 

 

 

 题解:

  • 正解:(紫书P206
  • IDA*,迭代加深搜索!一层一层地搜;用dfs的空间开销解决bfs的问题,并且方便了剪枝;有现成的系统栈能调用,还不用打堆;代码量小,易写易调试。
  •  
  • 以把原分数分解成的分数个数K为层数,从一开始的状态按照分母从小到大的顺序搜索。若在某一层搜到了解并且这一层已经搜完了,那这一层的最优解一定是整个问题的最优解。
  • 假设现在要分解的分数是a/b
  • 若当前原分数已经分解成为超过K个分数,直接返回即可。
  • a能整除b,那分解结束了,最后一个分母是b/a。用当前的解去更新答案,如果没有答案或当前解包含的分母个数少于答案或当前解包含的分母个数等于答案且当前解的最大分母比答案大,则当前解即为答案。
  • 否则,要枚举i,使得ab=ab′+1i,使i作为当前解的一部分,进入下一层递归。
  • i的范围如何确定?
  • 首先i要大于等于[ba],只有这样,才能使ab≥1i,这样的i才满足题意;其次i要大于当前解中分母最大的元素,这是搜索顺序决定的。同时i的值不能太大,要满足当前的分数有能分解成K个以内分数的可能性,假设i作为第step个分母,那么第step+1到第K个分母都应大于i,这些分数的和小于Kstepi,要有解,则必须1i+Kstepi=Kstep+1iab,即i[b(Kstep+1)a],如果算出来的i大于int的最大值,那就以int的最大值为界,否则算一段时间就会爆掉的,体现为变成负数然后TLE。注意ab进入下层时要约分,否则爆掉的几率会大大增加。
  • 然后,就可以AC

 AC代码:

#include<cstdio>
#include<algorithm>
#define IN inline
#define R register
#define ll long long
using namespace std;
const int N=1e5+10;
int n;
ll as[N],sa[N];bool flag;
IN bool check(ll a,ll b,ll c,ll d){
    if(a*d>b*c) return 0;
    else return 1;
}
IN void dfs(ll x,ll y,ll f,int d){
    if(x<0)return;
    if(d==1){
        if(x==1&&y>=f){
            if(y<sa[1]){
                flag=1;
                sa[1]=y;
                for(int i=n;i>=2;i--) sa[i]=as[i];
            }
        }
        return ;
    }
    for(R ll i=f,g;check(x,y,d,i);i++){
        as[d]=i;g=__gcd(x*i-y,y*i);
        dfs((x*i-y)/g,y*i/g,i+1,d-1);
    }
}
int main(){
    int x,y;
    scanf("%d%d",&x,&y);
    flag=false;
    sa[1]=1e17;
    for(int i=1;;i++){
        n=i,dfs(x,y,1,i);
        if(flag){
            for(int i=n;i;i--) printf("%lld ",sa[i]);
            return 0;
        }
    }
    return 0;
}

 

 

以上是关于1288 埃及分数的主要内容,如果未能解决你的问题,请参考以下文章

codevs1288 埃及分数

codevs1288 埃及分数

埃及分数的拆分法

埃及分数

埃及分数式

[题解]「一本通 1.3 练习 1」埃及分数