• #10022. 「一本通 1.3 练习 1」埃及分数(迭代加深搜索)


    Aimee

    很显然我们并不知道到底会搜索出多少层

    但是最优解一定不会太大

    那么迭代加深搜索会是一个好的选择

    迭代加深要限制层数,这很显然

    那么就此来说,当就剩下一个分数可以选的时候

    我们要判断这个分数是不是单位分数,如果他是,再判断一下是不是最优解

    这样就解决了dfs中的一半(体积意义上)的问题

    if(de==1){
    		if(x==1&&y>tem[p]&&(Aimee==0||y<ans[Aimee])){
    			Aimee=++p;
    			tem[p]=y;
    			for(int i=1;i<=Aimee;++i){
    				ans[i]=tem[i];
    			}
    			p--;
    			return 1;
    		}
    		return 0;
    	}
    

    为什么每一次都要判断呢,因为求的是当前层数的最优解

    dfs的另外一个问题就是怎样向下推导

    这里有三个优化

    第一个优化

    很显然保证字母大小递增

    第二个优化

    由于优化1可知,我们选的分数越来越小

    那也就意味着后面的分数铁定比前面小
    所以说当前这个分数的分母为i的话

    (frac{1}{i} < frac{x}{y})

    这样取一个最大值就可以知道下界了

    第三个优化

    取的分数越来越小,那么之后所有的分数之和一定会小于他们都等于当前这个分数

    换言之,如果剩下的数都等于当前分数的话,肯定是要大于剩下的分数的数的

    那么也就是说,如果(frac{k}{i}>frac{x}{y})是一定要满足的

    不然绝无可能合法

    但是这样会损失精度

    这很讨厌,那就变成乘法(k*y>x*i)

    剪枝完成

    bool dfs(int de,int x,int y,int la){
    	if(de==1){
    		if(x==1&&y>tem[p]&&(Aimee==0||y<ans[Aimee])){
    			Aimee=++p;
    			tem[p]=y;
    			for(int i=1;i<=Aimee;++i){
    				ans[i]=tem[i];
    			}
    			p--;
    			return 1;
    		}
    		return 0;
    	}
    	bool key=0;
    	for(int i=max(la+1,jdn(x,y));de*y>x*i;++i){
    		int yy=y/gcd(y,i)*i;
    		int xx=x*(yy/y)-yy/i;
    		int gcdd=gcd(xx,yy);
    		xx/=gcdd;
    		yy/=gcdd; 
    		tem[++p]=i;
    		if(dfs(de-1,xx,yy,i)) key=1;
    		p--;
    	} 
    	return key;
    }
    

    注意一些gcd的小细节以及有可能一开始给了一个埃及分数,那样的话就不能拆分的

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m;
    int gcd(int x,int y){
    	return y==0?x:gcd(y,x%y); 
    }
    int p;
    int de=1;
    int ans[100001];
    int Aimee;
    int tem[100001];
    int jdn(int x,int y){
    	for(int i=2;i;++i){
    		if(i*x>y)
    		return i;
    	}
    	return 0;
    }
    void print(){
    	for(int i=1;i<=Aimee;++i){
    		cout<<ans[i]<<" ";
    	}
    	return ;
    }
    bool dfs(int de,int x,int y,int la){
    	if(de==1){
    		if(x==1&&y>tem[p]&&(Aimee==0||y<ans[Aimee])){
    			Aimee=++p;
    			tem[p]=y;
    			for(int i=1;i<=Aimee;++i){
    				ans[i]=tem[i];
    			}
    			p--;
    			return 1;
    		}
    		return 0;
    	}
    	bool key=0;
    	for(int i=max(la+1,jdn(x,y));de*y>x*i;++i){
    		int yy=y/gcd(y,i)*i;
    		int xx=x*(yy/y)-yy/i;
    		int gcdd=gcd(xx,yy);
    		xx/=gcdd;
    		yy/=gcdd; 
    		tem[++p]=i;
    		if(dfs(de-1,xx,yy,i)) key=1;
    		p--;
    	} 
    	return key;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	int gcdd=gcd(n,m);
    	n/=gcdd;
    	m/=gcdd;
    	if(n==1){
    		cout<<m;
    		return 0;
    	}
    	while(++de){
    		p=0;
    		if(dfs(de,n,m,1)){
    			print();
    			return 0;
    		}
    	}
    	return 0;
    }
    

    That's all,thanks。

  • 相关阅读:
    Nginx开发从入门到精通
    Nginx配置文件(nginx.conf)配置详解
    转贝叶斯推断及其互联网应用(一):定理简介
    Vim 使用入门快捷键
    从贝叶斯定理说开去
    转特征值和特征向量
    第四章 特征值与特征向量
    numpy基础入门
    python range函数与numpy arange函数
    转悠望南山 Python闲谈(二)聊聊最小二乘法以及leastsq函数
  • 原文地址:https://www.cnblogs.com/For-Miku/p/14258942.html
Copyright © 2020-2023  润新知