在古埃及,人们使用单位分数的和(形如
1
a
\frac{1}{a}
a1的,
a
a
a是自然数)表示一切有理数。
如:
2
3
=
1
2
+
1
6
\frac{2}{3}=\frac{1}{2} + \frac{1}{6}
32=21+61,但不允许
2
3
=
1
3
+
1
3
\frac{2}{3}=\frac{1}{3} + \frac{1}{3}
32=31+31,因为加数中有相同的。
对于一个分数
a
b
\frac{a}{b}
ba,表示方法有很多种,但是哪种是最好的呢?
首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。
如:
19
45
=
1
3
+
1
12
+
1
180
\frac{19}{45}=\frac{1}{3}+\frac{1}{12}+\frac{1}{180}
4519=31+121+1801。
19
45
=
1
3
+
1
15
+
1
45
\frac{19}{45}=\frac{1}{3}+\frac{1}{15}+\frac{1}{45}
4519=31+151+451。
19
45
=
1
3
+
1
18
+
1
30
\frac{19}{45}=\frac{1}{3}+\frac{1}{18}+\frac{1}{30}
4519=31+181+301。
19
45
=
1
4
+
1
6
+
1
180
\frac{19}{45}=\frac{1}{4}+\frac{1}{6}+\frac{1}{180}
4519=41+61+1801。
19
45
=
1
5
+
1
6
+
1
18
\frac{19}{45}=\frac{1}{5}+\frac{1}{6}+\frac{1}{18}
4519=51+61+181。
最好的是最后一种,因为 1 18 \frac{1}{18} 181比 1 180 \frac{1}{180} 1801, 1 45 \frac{1}{45} 451, 1 30 \frac{1}{30} 301, 1 180 \frac{1}{180} 1801都大。
注意,可能有多个最优解。
如:
59
211
=
1
4
+
1
36
+
1
633
+
1
3798
\frac{59}{211} = \frac{1}{4} + \frac{1}{36} + \frac{1}{633} + \frac{1}{3798}
21159=41+361+6331+37981。
59 211 = 1 6 + 1 9 + 1 633 + 1 3798 \frac{59}{211} = \frac{1}{6} + \frac{1}{9} + \frac{1}{633} + \frac{1}{3798} 21159=61+91+6331+37981。
由于方法一与方法二中,最小的分数相同,因此二者均是最优解。
给出 a , b a, b a,b,编程计算最好的表达方式。保证最优解满足:最小的分数 ≥ 1 1 0 7 \geq \frac{1}{10^7} ≥1071
输入格式
一行两个整数,分别为a和b的值
输出格式
输出若干个数,自小到大排列,依次是单位分数的字母。
数据范围
0 < a < b < 1000 0<a<b<1000 0<a<b<1000
输入样例:
19 45
输出样例:
5 6 18
做法:
迭代加深
迭代加深就是一种深搜和广搜的结合,有些题目写的时候有些状态会一直往下做而超时,所以我们可以设定一个深度,做到这个深度就返回,如果找不到答案就继续做。
就像这样:
没找到答案,继续找
找到了答案就停止,并输出答案
这种方法就是DFS的空间
,BFS的时间
就可以把答案算出来了。
然后在搜索里面从小到大枚举字母字母的数值,
但是需要满足两个条件:
- 要保证枚举出来的从小到大
- 最大的字母越小越好
但是 a a a和 b b b都是 > 1000 >1000 >1000的
所以要加个剪枝来减小枚举分母的范围,如果要分解
a
b
\frac{a}{b}
ba,还剩x个数
则最大的分母不会超过ceil(
b
x
a
\frac{bx}{a}
abx)
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define LL long long
#define MAXN 1005
int maxd;
int ans[MAXN], tmp[MAXN];
bool cmp(int d)
{
for(int i = d; i >= 0; i--)
if(ans[i] != tmp[i])
return (ans[i] == 0 || tmp[i] < ans[i]) && (tmp[i] > 0);
return false;
}
LL gcd(LL a, LL b)
{
return b == 0 ? a : gcd(b, a % b);
}
bool dfs(int d, LL last, LL a, LL b)
{
if(d == maxd)
{
if(b % a)
return false;
tmp[d] = b / a;
if(cmp(d))
memcpy(ans, tmp, sizeof(ans));
return true;
}
bool flag = false;
last = max(last, b / a + 1);
for(int i = last; ;i++)
{
if(b * (maxd + 1 - d) <= i * a) //剪枝
break;
tmp[d] = i;
LL a1 = a * i - b, b1 = b * i;
LL t = gcd(a1, b1);
if(dfs(d + 1, i + 1, a1 / t, b1 / t))
flag = true;
}
return flag;
}
int main()
{
LL a, b;
scanf("%lld %lld", &a, &b);
for(maxd = 2; ; maxd++)
if(dfs(0, (b / a + 1), a, b))
break;
for(int i = 0; i <= maxd; i++)
printf("%d ", ans[i]);
return 0;
}