Description
在古埃及,人们使用单位分数的和(形如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),编程计算最好的表达方式。
Input
a b
Output
若干个数,自小到大排列,依次是单位分数的分母。
Sample Input
19 45
Sample Output
5 6 18
题解
迭代的入门经典题...然而我现在才做...
我们将深度迭代,搜索。
由于要使最小的分数最大,所以我们要边搜的时候记录当前状况下的最优解。
加个$A*$。
我们用估价函数算出枚举分母的范围区间。
注意开$int$会爆。
1 #include<map> 2 #include<ctime> 3 #include<cmath> 4 #include<queue> 5 #include<stack> 6 #include<cstdio> 7 #include<string> 8 #include<vector> 9 #include<cstring> 10 #include<cstdlib> 11 #include<iostream> 12 #include<algorithm> 13 #define LL long long 14 #define RE register 15 #define IL inline 16 using namespace std; 17 const LL INF=~0u>>1; 18 19 LL keep[100],ans[100]; 20 LL gcd(LL a,LL b) {return b ? gcd(b,a%b):a;} 21 22 LL a,b,lim; 23 24 void Dfs(LL cen,LL x,LL y) 25 { 26 if (cen>lim) return; 27 LL g=gcd(x,y);x/=g;y/=g; 28 if (x==1&&y>keep[cen-1]) 29 { 30 keep[cen]=y; 31 if (keep[cen]<ans[cen]) memcpy(ans,keep,sizeof(ans)); 32 return; 33 } 34 LL s=y/x; 35 if (keep[cen-1]>=s) s=keep[cen-1]+1; 36 LL t=y*(lim-cen+1)/x; 37 for (LL i=s;i<=t;i++) 38 { 39 keep[cen]=i; 40 Dfs(cen+1,i*x-y,y*i); 41 } 42 } 43 44 int main() 45 { 46 scanf("%lld%lld",&a,&b); 47 for (;;lim++) 48 { 49 ans[lim]=INF; 50 Dfs(1,a,b); 51 if (ans[1]>0&&ans[1]<INF) 52 { 53 for (RE LL i=1;i<=lim;i++) printf("%lld ",ans[i]); 54 return 0; 55 } 56 } 57 return 0; 58 }
时间: 2024-11-09 02:16:06