题目描述﹡﹡﹡﹡﹡
在古埃及,人们使用单位分数的和(形如 1/a 的,a 是正整数)表示一切有理数。
如:2/3 = 1/2 + 1/6,但不允许 2/3 = 1/3 + 1/3,因为加数中有相同的。
对于一个分数 a/b ,表示方法有很多种,但是哪种最好呢?
首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。
如:
19/45 = 1/3 + 1/12 + 1/180
19/45 = 1/3 + 1/15 + 1/45
19/45 = 1/3 + 1/18 + 1/30
19/45 = 1/4 + 1/6 + 1/180
19/45 = 1/5 + 1/6 + 1/18
最好的是最后一种,因为 1/18 比 1/180、1/45、1/30、1/180 都要大。
给出a、b (0 < a < b < 1000),试编程计算最好的表达方式。
输入格式
输入只有一行:a、b,表示需要表示的分数 a/b (0 < a < b < 1000)。
输出格式
一行,依次给出最好的表达方式中各个单位分数的分母(保证都在 32 位整型范围内)。
迭代深化,但实现起来很难,而且RQ上数据还有问题。
刚开始做的时候 函数传递的参数被我弄成浮点型,所以就game over了。
别人的题解 函数传递的是除数于被除数。
关键是剪枝。
首先下一个分母一定比上一个大,所以所有的分母必须单调递增,所以1/分母 单调递减。
若 tot 为后n 位 1/分母 的总和,则 tot/n 为后n 位 1/分母 的平均值,可知,当下的分母小于 平均值的倒数。
所以 搜索的范围就求出来了。
#include<iostream>
using namespace std;
long long a,b,g;
int l,ans[100],best[100];
bool p=0;
long long gcd(long long x,long long y){
long long z;
while(x!=0)
{z=x;x=y%x;y=z;}
return y;
}
void Dfs(long long x,long long y,int h){
int i;
if(h==l)
{
g=gcd(x,y);
x/=g;y/=g;
if(x==1&&y>0&&y>ans[h-1])
{
if(p==0||(p==1&&y<best[h]))
{
for(i=1;i<h;++i) best[i]=ans[i];
best[h]=y;p=1; return ;
}
}
return ;
}
int mi=ans[h-1]+1,ma=(l-h+1)*y/x+2;
long long xx,yy;
for(i=mi;i<=ma;++i)
{
ans[h]=i;
xx=x*i-y;yy=y*i;
Dfs(xx,yy,h+1);
}
}
int main()
{
cin>>a>>b;
g=gcd(a,b);
a/=g;b/=g;
if(a==1) {cout<<b<<endl;return 0;}
for(l=2;;++l)
{Dfs(a,b,1);if(p) break;}
for(int i=1;i<l;++i)
cout<<best[i]<<" ";
cout<<best[l]<<endl;
// system("pause");
return 0;
}