zoukankan      html  css  js  c++  java
  • #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。

  • 相关阅读:
    在日本被禁止的コンプガチャ設計
    Starling常见问题解决办法
    Flixel引擎学习笔记
    SQLSERVER中修复状态为Suspect的数据库
    T4 (Text Template Transformation Toolkit)实现简单实体代码生成
    创建Linking Server in SQL SERVER 2008
    Linq to Sql 与Linq to Entities 生成的SQL Script与分页实现
    Linq to Entity 的T4 模板生成代码
    在VisualStudio2008 SP1中调试.net framework 源代码
    使用HttpModules实现Asp.net离线应用程序
  • 原文地址:https://www.cnblogs.com/For-Miku/p/14258942.html
Copyright © 2011-2022 走看看