zoukankan      html  css  js  c++  java
  • Codevs 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
    搜索

    /*
    经典迭代搜索问题.
    打了将近俩小时orz. 
    这题主要是剪枝(能保证正确性就剪剪剪233).
    分数个数少的优,最大的分母小优.
    先搞一个解答树的深度.
    然后从小枚举分母.
    剪枝的话.
    (1) t=max(t,get_m(x,y))//当前最小分母,
    第一次没加T了,原来是有个地方没return 不加也能过但要特判2333.
    (2) if((maxd-d+1)*y<=x*i) return 可行性剪枝(这题就靠它了原理so easy).
    (3) 剪掉不合法的最后一层 可以降常数.
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define MAXN 101
    #define LL long long
    using namespace std;
    int tot,a,b,maxd=1;
    LL ans[MAXN],s[MAXN];
    bool flag;
    bool check(int x)
    {
        if(ans[maxd]>s[maxd]) return true;
        for(int i=1;i<=x;i++)
          if(ans[i]==ans[0]) return true;
        return false;
    }
    int get_m(LL x,LL y)
    {
        tot=1;
        while(x*tot<y) tot++;
        return tot-1;
    }
    int gcd(LL x,LL y)
    {
        if(!y) return x;
        return gcd(y,x%y);
    }
    void dfs(LL x,LL y,int d,int t)
    {
        if(d==maxd){
            if(x!=1) return ;
            s[maxd]=y;
            if(check(maxd))
            {
                for(int i=1;i<=maxd;i++) ans[i]=s[i];
                flag=true;
                return ;
            }
            return ;
        }
        t=max(t,get_m(x,y));
        for(int i=t+1;;i++)
        {
            if((maxd-d+1)*y<=x*i) return ;
            LL xx=x*i-y,yy=y*i;s[d]=i;
            int g=gcd(xx,yy);xx/=g,yy/=g;
            if(d+1==maxd&&xx!=1) continue;
            dfs(xx,yy,d+1,i);
        }
        return ;
    }
    int main()
    {
        memset(ans,127/3,sizeof ans);
        scanf("%d %d",&a,&b);
        for(;;maxd++)
        {
            dfs(a,b,1,get_m(a,b));
            if(flag) break;
        }
        for(int i=1;i<=maxd;i++) printf("%d ",ans[i]);
        return 0;
    }
  • 相关阅读:
    [每日一题] OCP1z0-047 :2013-07-29 视图――别名
    Java动态规划实现最短路径问题
    Java动态规划实现最短路径问题
    Java实现堆排序问题(变治法)
    Java实现堆排序问题(变治法)
    Java实现堆排序问题(变治法)
    Java实现堆排序问题(变治法)
    Java实现堆排序问题(变治法)
    Java实现8枚硬币问题(减治法)
    Java实现8枚硬币问题(减治法)
  • 原文地址:https://www.cnblogs.com/nancheng58/p/10068166.html
Copyright © 2011-2022 走看看