本文搬运自本人初中博客园博客,若图片加载不出来,可到原文查看:https://www.cnblogs.com/zhangtingxi/p/15724727.html

题目链接

题目

古埃及,人们使用单位分数的和(形如 1a\dfrac{1}{a} 的,aa 是自然数)表示一切有理数。如:23=12+16\dfrac{2}{3} = \dfrac{1}{2} + \dfrac{1}{6},但不允许 23=13+13\dfrac{2}{3} = \dfrac{1}{3} + \dfrac{1}{3},因为加数中有相同的。对于一个分数 ab\dfrac{a}{b},表示方法有很多种,但是哪种最好呢?首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。如:

\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}

最好的是最后一种,因为 118\dfrac{1}{18}1180,145,130,118\dfrac{1}{180}, \dfrac{1}{45}, \dfrac{1}{30}, \dfrac{1}{18} 都大。
注意,可能有多个最优解。如:

\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,ba,b,编程计算最好的表达方式。保证最优解满足:最小的分数 1107\ge \cfrac{1}{10^7}

思路

方法就是爆搜。

可以用迭代加深搜索来实现,枚举总共用多少个分数,然后搜下去。

注意输入的数要先约分,不然我像我一样一直RE一个点。

总结

  1. 遇到此类题目,不要害怕,要勇敢去打。
  2. 对于题目中不确定的(例如个数),可以用迭代加深搜索,因为前面的全部搜一次都不够最后一层搜得大。
  3. 题目中涉及分数运算要经常记得通分。

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

// Problem: P1763 埃及分数
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1763
// Memory Limit: 128 MB
// Time Limit: 1000 ms
// Powered by CP Editor (https://github.com/cpeditor/cpeditor)

#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 M
//#define mo
#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==3) return ;
// if(k<2)
// printf(">%lld %lld %lld %lld\n", lmt, k, x, y);
if(k>lmt)
{
// printf("%lld %lld\n", x, y);
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;
// printf("(%lld, %lld<=i*%lld)\n", ans[k-1]+1, m*y, (n*y-m*x));
// if(k<3)
// printf("%lld<=i<=%lld\n", max(ans[k-1]+1, yn/xn), yn*(lmt-k+1)/xn);
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;
// printf("(%lld) ", z);
dfs(lmt, k+1, newx, newy);
}
}

signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
n=read(); m=read();
k=gcd(n, m); n/=k; m/=k;
for(i=ans[0]=1; !flg; ++i)
{
// printf("%lld\n", i);
tot[i]=1e12, dfs(i, 1, 0, 1);
}

// printf("%lld\n", i);
for(j=1; j<i; ++j) printf("%lld ", tot[j]);
return 0;
}
文章作者: zhangxixi
文章链接: http://zhangxixi2008.github.io/post/4273051d
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 zhangxixi的博客