题解 洛谷 P1763 埃及分数

这么经典的题目居然这么少人写题解,那么我这个蒟蒻就来写一发 Java 题解罢!

由于这道题的搜索树深度无限,所以排除掉深搜;每层能扩展的广度也无限,所以排除广搜。那么,我们就只能使用一种深搜广搜结合的算法——迭代加深搜索。迭代加深搜索就是不断放宽搜索树最大深度的深搜。

我们还需要一些剪枝优化。

  • 优化1:为了避免重复搜索,我们强制让分母递增。
  • 优化2:由于分母递增,那么如果当前搜索的分数过小,在搜索树深度有限的情况下(这也是使用迭代加深的原因之一)就永远凑不够数,所以可以剪枝。这个优化可以把无限的扩展宽度剪成有限的,非常强力。
  • 优化3:由于 Java 巨大的常数,所以可以卡时,如果快要超时就直接输出。
import java.util.Scanner;

class frac{//一个支持加减法和比较的分数类
    long a,b;
    long gcd(long x,long y){
        if(y==0)return x;
        else return gcd(y,x%y);
    }
    frac(){a=0;b=1;}
    frac(long _a,long _b){a=_a;b=_b;yuefen();}
    void yuefen(){
        long d=gcd(a,b);
        a/=d;b/=d;
    }
    frac plus(frac r){
        frac res=new frac(a*r.b+r.a*b,b*r.b);
        res.yuefen();
        return res;
    }
    frac sub(frac r){
        frac res=new frac(a*r.b-r.a*b,b*r.b);
        res.yuefen();
        return res;
    }
    long cmp(frac r){
        frac t1=new frac(a*r.b,b*r.b),t2=new frac(r.a*b,b*r.b);
        return t1.a-t2.a;
    }
    boolean same(frac r){
        yuefen();r.yuefen();
        return a==r.a&&b==r.b;
    }
}

public class Main{
    static frac to;
    static long[] s=new long[114514],best=new long[114514];
    static boolean flag=false;
    static long clk;
    static void dfs(int step,int maxstep,frac now){
        if(++clk>1000000){//卡时
            return;
        }
        if(step>maxstep){
            if(now.same(to)){
                if(best[1]==0||s[step-1]<best[step-1]){//找最优解
                    for(int i=1;i<=step;i++){
                        best[i]=s[i];
                    }
                    flag=true;
                }
            }
            return;
        }
        long pre=s[step-1],res=maxstep-step+1;
        frac tmp=to.sub(now);
        for(long i=Math.max(pre+1,tmp.b/tmp.a)/*优化1*/;i<=tmp.b*res/tmp.a/*优化2*/;i++){
            s[step]=i;
            dfs(step+1,maxstep,now.plus(new frac(1,i)));
        }
    }
    public static void main(String[] args){
        Scanner input=new Scanner(System.in);
        to=new frac();
        to.a=input.nextLong();to.b=input.nextLong();
        int i=0;
        s[0]=1;
        while(!flag){//迭代加深
            i++;
            dfs(1,i,new frac(0,1));
        }
        for(int j=1;j<=i;j++){
            System.out.printf("%d ",best[j]);
        }
        input.close();
    }
}
posted @ 2022-02-14 17:37  ztx-  阅读(72)  评论(0编辑  收藏  举报