zoukankan      html  css  js  c++  java
  • UVA12558 Egyptian Fractions (HARD version)(埃及分数)

    传送门

    题目大意

    给出一个真分数 a/b,要求出几个互不相同的埃及分数(从大到小),使得它们之和为 a/b

    (埃及分数意思是分子为1的分数,详见百度百科

    如果有多组解,则分数数量少的优先

    如果分数数量一样则分母最大的要尽量小,如果最大的分母同样大,则第二大的分母尽量小,以此类推

    为了加大难度,会给出k个不能作为分母的数

    (2<=a,b<=876,k<=5 并且 a,b 互质)

    首先想的是数论,但是呢

    推不出来...

    然后发现a,b好像不大

    貌似可以搜索

    但是呢

    不知道上界...

    那就迭代加深搜索呗

    然后想想怎么剪枝

    如果知道 a/b,要怎么求出最小 k 使 1/k < a/b 呢(注意符号)

    易知 a/b 为真分数 ,a,b,k均为整数
    所以 a<b
    所以必定有整数 x,y 使得 x*a+y=b 且y<a
    所以可得 int(b/a)=int( (x*a+y) /a )=int(x*a/a)+int(y/a) = x
    因为 int(b/a)<=b/a,int(b/a)=x
    所以 x+1 > b/a , 所以 int(b/a)+1>b/a,
    所以1/(x+1) < a/b 又 1/int(b/a)=1/x >=a/b 所以 x+1就是最小的 k 使得 1/k < a/b 所以 k=int(b/a) + 1 证明完毕

    知道了 k 的下界,那还要求 k 的上界

    显然每次求的分母肯定要比上一次大(题目要求)

    所以如果后面所有的分母都为 k ,加起来还没有当前要求的数大,那就不要再搜下去了,再下去也不会有结果的

    然后就可以搜了,至于判断是否可用我用的是set

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<set>
    using namespace std;
    const int N=1e5+7;
    set <long long> p;
    long long t,A,B,n,mxdep;
    long long ans[N],w[N];
    bool flag;
    inline long long gcd(long long a,long long b)
    {
        return b ? gcd(b,a%b) : a;
    }//gcd是为了约分
    inline bool pd()
    {
        for(int i=mxdep;i;i--)
            if(ans[i]!=w[i])
                return ans[i]&&ans[i]<w[i];
        return 0;
    }//判断答案是否更优
    inline void dfs(long long dep,long long a,long long b,long long mi)
    {
        if(dep==mxdep)
        {
            if(b%a||(b<(mi-1)*a+1)||p.count(b/a)) return;//判断合法性
            //如果a/b可化为 1/k 的形式并且 1/k 可以选
            w[dep]=b/a;
            if(pd()) return;//判断答案是否更优
            memcpy(ans,w,sizeof(w)); flag=1;//更新
            return;
        }
        mi=max(mi,b/a+1);//求出下界
        for(long long i=mi;i;i++)
        {
            if( (mxdep-dep+1)*b<=i*a ) return;//上界
            if(p.count(i)) continue;//判断合法
            w[dep]=i;//记录路径
            long long xa=a*i-b,xb=i*b;//通分
            long long z=gcd(xa,xb);
            dfs(dep+1,xa/z,xb/z,i+1);//约分,向下一层
        }
    }
    int main()
    {
        cin>>t;
        for(long long i=1;i<=t;i++)
        {
            flag=0; mxdep=1;
            cin>>A>>B>>n;
            long long c;
            p.clear();//细节
            while(n--) scanf("%lld",&c),p.insert(c);//存储不合法的数
            while(mxdep++)
            {
                memset(ans,0,sizeof(ans));
                dfs(1,A,B,B/A+1);
                if(flag) break;
            }//迭代加深
            printf("Case %lld: %lld/%lld=1/%lld",i,A,B,ans[1]);
            for(int i=2;i<=mxdep;i++)
                printf("+1/%lld",ans[i]);
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    linux命令之------Linux文档编辑
    linux命令之------Linux文件系统具体目录
    linux命令之------快捷键说明
    linux命令之------Tar解压缩
    CentOS7如何关闭防火墙
    centos7中运行ifconfig提示-bash: ifconfig: command not found
    System.getProperty、PropConfig.loadConfig应用
    Java高并发syncronized深入理解
    json的工具以及浏览器排序问题
    Mockito: InvalidUseOfMatchersException
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9612583.html
Copyright © 2011-2022 走看看