题目:埃及分数
题目描述﹡﹡﹡﹡﹡
在古埃及,人们使用单位分数的和(形如 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; }