本文搬运自本人初中博客园博客,若图片加载不出来,可到原文查看:https://www.cnblogs.com/zhangtingxi/p/15724727.html
题目
古埃及,人们使用单位分数的和(形如 1 a \dfrac{1}{a} a 1 的,a a a 是自然数)表示一切有理数。如:2 3 = 1 2 + 1 6 \dfrac{2}{3} = \dfrac{1}{2} + \dfrac{1}{6} 3 2 = 2 1 + 6 1 ,但不允许 2 3 = 1 3 + 1 3 \dfrac{2}{3} = \dfrac{1}{3} + \dfrac{1}{3} 3 2 = 3 1 + 3 1 ,因为加数中有相同的。对于一个分数 a b \dfrac{a}{b} b a ,表示方法有很多种,但是哪种最好呢?首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。如:
\begin{aligned}
\frac{19}{45} &= \frac{1}{3} + \frac{1}{12} + \frac{1}{180}\\
\frac{19}{45} &= \frac{1}{3} + \frac{1}{15} + \frac{1}{45}\\
\frac{19}{45} &= \frac{1}{3} + \frac{1}{18} + \frac{1}{30}\\
\frac{19}{45} &= \frac{1}{4} + \frac{1}{6} + \frac{1}{180}\\
\frac{19}{45} &= \frac{1}{5} + \frac{1}{6} + \frac{1}{18}\\
\end{aligned}
最好的是最后一种,因为 1 18 \dfrac{1}{18} 18 1 比 1 180 , 1 45 , 1 30 , 1 18 \dfrac{1}{180}, \dfrac{1}{45}, \dfrac{1}{30}, \dfrac{1}{18} 180 1 , 45 1 , 30 1 , 18 1 都大。
注意,可能有多个最优解。如:
\begin{aligned}
\frac{59}{211} &= \frac{1}{4} + \frac{1}{36} + \frac{1}{633} + \frac{1}{3798}\\
\frac{59}{211} &= \frac{1}{6} + \frac{1}{9} + \frac{1}{633} + \frac{1}{3798}\\
\end{aligned}
由于方法一与方法二中,最小的分数相同,因此二者均是最优解。
给出 a , b a,b a , b ,编程计算最好的表达方式。保证最优解满足:最小的分数 ≥ 1 10 7 \ge \cfrac{1}{10^7} ≥ 1 0 7 1 。
思路
方法就是爆搜。
可以用迭代加深搜索来实现,枚举总共用多少个分数,然后搜下去。
注意输入的数要先约分,不然我像我一样一直RE一个点。
总结
遇到此类题目,不要害怕,要勇敢去打。
对于题目中不确定的(例如个数),可以用迭代加深搜索,因为前面的全部搜一次都不够最后一层搜得大。
题目中涉及分数运算要经常记得通分。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 #include <bits/stdc++.h> using namespace std;#define int long long inline int read () {int x=0 ,f=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )f=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+ (x<<3 )+(ch^48 );ch=getchar ();}return x*f;} #define N 10000010 int n, m, i, j, k; int ans[N], tot[N], flg; int gcd (int x, int y) { while (y) { int z=x%y; x=y; y=z; } return x; } void dfs (int lmt, int k, int x, int y) { if (k>lmt) { if (x==n&&y==m) { if (ans[lmt]<tot[lmt]) for (int i=1 ; i<=lmt; ++i) tot[i]=ans[i]; flg=1 ; } return ; } int xn=n*y-m*x, yn=m*y; if (yn==0 ) return ; int i, z, newx, newy; for (i=max (ans[k-1 ]+1 , yn/xn); i<=yn*(lmt-k+1 )/xn; ++i) { ans[k]=i; newx=x*i+y; newy=y*i; if (m*newx>n*newy) continue ; z=gcd (newx, newy); if (z>1 ) newx/=z, newy/=z; dfs (lmt, k+1 , newx, newy); } } signed main () { n=read (); m=read (); k=gcd (n, m); n/=k; m/=k; for (i=ans[0 ]=1 ; !flg; ++i) { tot[i]=1e12 , dfs (i, 1 , 0 , 1 ); } for (j=1 ; j<i; ++j) printf ("%lld " , tot[j]); return 0 ; }
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 zhangxixi的博客 !