codevs 1288 埃及分數

題目大意:給出一個分數,要求求出最少的x分之1的形式,如果個數相同,要求最小的數字最大。

考慮搜索,因爲總個數不確定,使用IDDFS,每次確定一個長度,對於每一個位置從可以成立的最小值開始枚舉。

對於最終情況:如果這次的a爲1,並且b比前面的一次大,那麼就是最終情況,這時如果這個長度沒出現過,那麼當前序列

作爲答案,如果出現過,那麼選擇最大的最後一位作爲答案。

對於搜索,每一次的新值的最小值一定要比當前的b/a大,這樣1/i就比a/b大,同時也要比上一個選擇i要大,因爲我們選擇的

答案是遞增的。對於最大值,極限情況就是後續都選擇i時,整體要比a/b大,所以i<(now-dep+1)*b/a。

如果最大值大於int要縮成int的極限值-1(玄學優化。。。),如果這個長度已經有過答案了,那麼極限值要比目前答案的最小值

大,這樣纔有意義。傳入下一層的就是a/b-1/i的對應分子和分母。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll a,b,ans[15],tmp[15],now,inf=2147483647;
ll gcd(ll x,ll y)
{
	if(y==0)return x;
	return gcd(y,x%y);
}
int flag;
void dfs(ll dep,ll na,ll nb)
{
	if(dep>now)return;//這個地方也可以和下面的判斷寫在一起,當然瞭如果有最優答案早就結束了
	if(na==1&&nb>tmp[dep-1])
	{
		tmp[dep]=nb;
		if(!flag||tmp[dep]<ans[dep])
		{
			memcpy(ans,tmp,sizeof(tmp));
		}
		flag=1;return;
	}
	ll st=max(nb/na,tmp[dep-1]+1),ed=(now-dep+1)*nb/na;
	if(ed>inf)ed=inf-1;
	if(flag&&ed>=ans[now])ed=ans[now]-1;
	for(ll i=st;i<=ed;i++)
	{
		tmp[dep]=i;
		ll ty=gcd(na*i-nb,nb*i);
		dfs(dep+1,(na*i-nb)/ty,nb*i/ty);
	}
}

int main()
{
	scanf("%lld%lld",&a,&b);
	ll c=gcd(a,b);
	a/=c,b/=c;
	if(a==1)
	{
		printf("%lld\n",b);
		return 0;
	}
	tmp[0]=1;
	for(now=1;;now++)
	{
		dfs(1,a,b);
		if(flag)
		{
			for(int i=1;i<=now;i++)
			{
				printf("%lld ",ans[i]);
			}
			return 0;
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章