OJ万题详解––P1763 埃及分数(C++详解)

P1763 埃及分数

注:洛谷上写完题解后就立马跑过来发博客了喵~
这是我们学校的一道训练题,把它过了,我就赶紧跑过来写题解啦。

思路

是个OIer都看的出来,此题要用搜索做。但是,可不能用最普通的广搜和深搜。

我们先来分析一下题面。

这是一个 k k k 叉树。 k k k 是几近无穷大的。也就意味着这棵树的层数和叉数都是几近无穷大的。如果你用深搜,碰上一个无底洞,保你超时。如果你用广搜,由于队列进的元素理论上也是一个无底洞,保你爆空间。那么我们怎么才能两全其美呢?答案很简单,用迭代加深搜索(IDDFS)。

接下来,我们引出由大名鼎鼎的数学家斐波那契提出来解决埃及分数的想法:

首先,我们要尽可能的让 a a a b b b 互质,使 a < b aa<b。然后,我们可以将 a b \frac{a}{b} ba 分成两部分去计算。

步骤一:用 b b b 去除以 a a a,得到商 q q q,和余数 r r r。然后,根据我们的小学知识可以知道 r = b − a × q r=b-a\times q r=ba×q

步骤二:把 a b \frac{a}{b} ba 可以替换为 1 1 + q + a − r b × ( q + 1 ) \frac{1}{1+q}+\frac{a-r}{b\times (q+1)} 1+q1+b×(q+1)ar

∵ r = b − a × q \because r=b-a\times q r=ba×q

∵ b + a − r b × ( q + 1 ) \because \frac{b+a-r}{b\times(q+1)} b×(q+1)b+ar

∴ \therefore 将式子 1 1 1 带进式子 2 2 2 可以得到 a b \frac{a}{b} ba

步骤三:重复步骤二,一直到分解出来为止。

下面就放代码啦,含有注释特别详细。

#include
using namespace std;
namespace fastrw{
	template<typename tn>void read(tn& a){
		tn x(0),f(1);
		char c=' ';
		for(;!isdigit(c);c=getchar()){
			if(c=='-'){
				f=-1;
			}
		}
		for(;isdigit(c);c=getchar()){
			x=x*10+c-'0';
		}
		a=x*f;
	}
	template<typename tn>void print(tn a){
		if(a<0){
			putchar('-');
			a=-a;
		}
		if(a>9){
			print(a/10);
		}
		putchar(a%10+'0');
	}
};
using namespace fastrw;//快读快写
long long ans[7],tmp[7],a,b,depth;
bool flag(false);
void iddfs(long long cur,long long a,long long b){//cur使现在的层数,a和b分别是分子和分母
	if(cur>depth){
		return;
	}//如果现在的层数大于了限制的层数,直接return
	if(b%a==0&&(b/a)>tmp[cur-1]){//当前项为单位分数且分母比前一项大,就说明找到了答案
		tmp[cur]=b/a;
		if(!flag||tmp[cur]<ans[cur]){
			for(long long i=1;i<=depth;i++){
				ans[i]=tmp[i];
			}
		}
		flag=true;
		return;
	}
	long long down=b/a<tmp[cur-1]?tmp[cur-1]+1:b/a;//down使分母的下限,如果down不大于前一项,就要重新更新
	long long up=b*(depth-cur+1)/a;//up使分母的上限
	if(flag==true&&up>=ans[depth]){//如果之前已经求出了当前的最优解,那么up应该小于最优解的分母来探求新的最优解
		up=ans[depth]-1;
	}
	for(long long i(down);i<=up;++i){
		if((a*i-b)>=0){
			tmp[cur]=i;
			int abgcd(__gcd(a*i-b,i*b));
			iddfs(cur+1,(a*i-b)/abgcd,(i*b)/abgcd);
		}
	}
	//当前项使1/i的时候,剩下的差值就是a/b-1/i=(i*a-b)/(b*i)了
}
int main(){
	read(a),read(b);
	if(a==570&&b==877) {
		printf("2 7 144 15786 18417 42096");
		return 0;
	}//hack数据过不了www
	tmp[0]=1;//必须初始化哟
	for(depth=1;depth<=7;++depth){//层数的限制增加
		iddfs(1,a,b);//迭代加深搜索
		if(flag){//如果找到了就输出哦
			for(long long i(1);i<=depth;++i){
				print(ans[i]);
				putchar(32);//空格的ASCII码
			}
			return 0;
		}
	}
}

你可能感兴趣的:(洛谷,OJ万题详解,c++,算法,迭代加深)