迭代加深前置知识请看这里辣
题目描述
题目分析
这道题有两个限定条件,一个是要求分数的个数最小,还有一个是最小的分数最大
直接是肯定不行的,你只能满足其中一个条件
于是我们就想到了迭代加深
其中迭代加深限定的深度是用多少个分数
然后一波判断+比较就出来了
补充知识
斐波那契提出一种用贪心求解埃及分数的方法
- 先使
互质,即将原分数化成最简,且
- 令
,可得
- 将
记作
……①
……②
- 将①带入②就可以得到
- 而②通分后就是
- 然后我们就可以得到其中一个分数是
- 再把剩下的
继续分解,直到得到答案
于是我们就可以上代码了
代码实现::
#include<cstdio>
#include<cstring>
#define ll long long
#define rt
inline void read(long long &x) {
x=0;
int f=1;
char s=getchar();
for(;s<48||s>57;s=getchar())
if(s=='-')
f=-1;
for(;s>47&&s<58;s=getchar())
x=x*10+s-48;
x*=f;
}
inline void pr(long long x) {
if(x<0)
putchar('-'),x=-x;
if(x>9)
pr(x/10);
putchar(x%10+48);
}//快读快输不解释
ll ans[15],d[15],a,b,depth;
bool flag;
ll gcd(ll a,ll b) {//辗转相除法
ll t=a%b;
while(t)
a=b,b=t,t=a%b;
return b;
}
void iddfs(ll a,ll b,int k) {
if(k>depth)//超越最大深度了,而且还没有答案,必须return
rt;
if(b%a==0&&(b/a)>d[k-1]) {//d是答案数组
d[k]=b/a;//答案
if(!flag||d[k]<ans[k])//没找到||最大的小于最小的
memcpy(ans,d,sizeof(d));
flag=1;//已经找到答案
rt;
}
ll s=b/a;
if(s<=d[k-1])//上下限
s=d[k-1]+1;
ll t=b*(depth-k+1)/a;
if(flag&&t>=ans[depth])
t=ans[depth]-1;
for(ll i=s;i<=t;i++) {
ll m=gcd(i*a-b,b*i);
d[k]=i;
iddfs((i*a-b)/m,b*i/m,k+1);//斐波那契贪心法求解
}
}
int main() {
d[0]=1;
read(a),read(b);
for(depth=1;depth<=10;depth++) {//至于为什么这里是10,能过就行了,只是开得更大就更保险,也更费时
iddfs(a,b,1);//迭代加深
if(flag) {//已经有答案
pr(ans[1]);
for(int i=2;i<=depth;i++)
putchar(' '),pr(ans[i]);
break;
}
}
}
大家还有什么不懂的,一起讨论讨论