在古埃及,人们使用单位分数的和(形如1a\frac{1}{a}a1的,aaa是自然数)表示一切有理数。
如:23=12+16\frac{2}{3}=\frac{1}{2} + \frac{1}{6}32=21+61,但不允许23=13+13\frac{2}{3}=\frac{1}{3} + \frac{1}{3}32=31+31,因为加数中有相同的。
对于一个分数ab\frac{a}{b}ba,表示方法有很多种,但是哪种是最好的呢?
首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。
如:
1945=13+112+1180\frac{19}{45}=\frac{1}{3}+\frac{1}{12}+\frac{1}{180}4519=31+121+1801。
1945=13+115+145\frac{19}{45}=\frac{1}{3}+\frac{1}{15}+\frac{1}{45}4519=31+151+451。
1945=13+118+130\frac{19}{45}=\frac{1}{3}+\frac{1}{18}+\frac{1}{30}4519=31+181+301。
1945=14+16+1180\frac{19}{45}=\frac{1}{4}+\frac{1}{6}+\frac{1}{180}4519=41+61+1801。
1945=15+16+118\frac{19}{45}=\frac{1}{5}+\frac{1}{6}+\frac{1}{18}4519=51+61+181。
最好的是最后一种,因为118\frac{1}{18}181比1180\frac{1}{180}1801,145\frac{1}{45}451,130\frac{1}{30}301,1180\frac{1}{180}1801都大。
注意,可能有多个最优解。
如:
59211=14+136+1633+13798\frac{59}{211} = \frac{1}{4} + \frac{1}{36} + \frac{1}{633} + \frac{1}{3798}21159=41+361+6331+37981。
59211=16+19+1633+13798\frac{59}{211} = \frac{1}{6} + \frac{1}{9} + \frac{1}{633} + \frac{1}{3798}21159=61+91+6331+37981。
由于方法一与方法二中,最小的分数相同,因此二者均是最优解。
给出a,ba, ba,b,编程计算最好的表达方式。保证最优解满足:最小的分数≥1107\geq \frac{1}{10^7}≥1071
输入格式
一行两个整数,分别为a和b的值
输出格式
输出若干个数,自小到大排列,依次是单位分数的字母。
数据范围
0<a<b<10000<a<b<10000<a<b<1000
输入样例:
19 45
输出样例:
5 6 18
做法:
迭代加深
迭代加深就是一种深搜和广搜的结合,有些题目写的时候有些状态会一直往下做而超时,所以我们可以设定一个深度,做到这个深度就返回,如果找不到答案就继续做。
就像这样:

没找到答案,继续找

找到了答案就停止,并输出答案
这种方法就是DFS的空间,BFS的时间就可以把答案算出来了。
然后在搜索里面从小到大枚举字母字母的数值,
但是需要满足两个条件:
- 要保证枚举出来的从小到大
- 最大的字母越小越好
但是aaa和bbb都是>1000>1000>1000的
所以要加个剪枝来减小枚举分母的范围,如果要分解ab\frac{a}{b}ba,还剩x个数
则最大的分母不会超过ceil(bxa\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;
}
本文介绍了古埃及分数的表示方法,强调了在寻找最优表示时,加数少且最小分数大的原则。通过举例展示了如何确定分数的最佳组合。并提出了一个编程问题,要求计算单位分数之和的最优解,其中最小分数大于等于10^7。为了解决这个问题,提出了迭代加深的搜索策略,结合深度优先搜索(DFS)和广度优先搜索(BFS),同时引入剪枝策略以限制枚举范围,确保在大数据情况下也能有效求解。
590

被折叠的 条评论
为什么被折叠?



