埃及分数

本文介绍了古埃及分数的表示方法,强调了在寻找最优表示时,加数少且最小分数大的原则。通过举例展示了如何确定分数的最佳组合。并提出了一个编程问题,要求计算单位分数之和的最优解,其中最小分数大于等于10^7。为了解决这个问题,提出了迭代加深的搜索策略,结合深度优先搜索(DFS)和广度优先搜索(BFS),同时引入剪枝策略以限制枚举范围,确保在大数据情况下也能有效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在古埃及,人们使用单位分数的和(形如 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

做法:

迭代加深

迭代加深就是一种深搜和广搜的结合,有些题目写的时候有些状态会一直往下做而超时,所以我们可以设定一个深度,做到这个深度就返回,如果找不到答案就继续做。

就像这样:
在这里插入图片描述
没找到答案,继续找
D1FD3t.md.png
找到了答案就停止,并输出答案
这种方法就是DFS的空间BFS的时间就可以把答案算出来了。

然后在搜索里面从小到大枚举字母字母的数值,
但是需要满足两个条件:

  1. 要保证枚举出来的从小到大
  2. 最大的字母越小越好
    但是 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值