[Codevs 1228]埃及分数
第一道迭代加深搜索,《算法竞赛入门经典》上的例题。
注意分母这个数字可能很大,所以要用long long
在寻找满足 \(1/c \leq a/b\) 的最小的 \(c\) 时,可以知道\(c=\lceil a/b \rceil\),注意要将\(a/b\)转换成double
类型.
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXD=1000+1;
ll ans[MAXD],v[MAXD];
inline ll get_first(ll a,ll b) {
for(ll c=1;;c++) {
if(a*c>=b) return c;
}
}
inline bool better_ans(int maxd) {
if(!ans[maxd] || v[maxd]!=ans[maxd]) return !ans[maxd] || v[maxd]<ans[maxd];
for(int i=1;i<maxd;i++) if(v[i]!=ans[i]) return v[i]<ans[i];
return false;
}
inline int gcd(ll x,ll y) {
return !y?x:gcd(y,x%y);
}
bool dfs(int d,int maxd,ll from,ll a,ll b) {
if(d==maxd) {
if(b%a) return false;
v[d]=b/a;
if(better_ans(maxd)) {
memcpy(ans,v,sizeof(v));
}
return true;
}
bool ok=false;
from=max(from,get_first(a,b));
for(ll i=from;;i++) {
if(b*(maxd+1-d)<=i*a) break;
v[d]=i;
ll y=b*i,x=a*i-b,g=gcd(max(x,y),min(x,y));
if(dfs(d+1,maxd,i+1,x/g,y/g)) ok=true;
}
return ok;
}
int main() {
int a,b;
scanf("%d %d",&a,&b);
if(a==1) {
printf("%d",b);
return 0;
}
int maxd;
for(maxd=2;;maxd++) {
memset(ans,0,sizeof(ans));
if(dfs(1,maxd,get_first(a,b),a,b)) break;
}
printf("%lld",ans[1]);
for(int i=2;i<=maxd;i++) {
printf(" %lld",ans[i]);
}
return 0;
}