洛谷P1763 埃及分数

传送门

题目描述

来源:BIO 1997 Round 1 Question 3
在古埃及,人们使用单位分数的和(形如 \dfrac{1}{a}
a
1

的,aa 是自然数)表示一切有理数。如:\dfrac{2}{3} = \dfrac{1}{2} + \dfrac{1}{6}
3
2

2
1

+
6
1

,但不允许 \dfrac{2}{3} = \dfrac{1}{3} + \dfrac{1}{3}
3
2

3
1

+
3
1

,因为加数中有相同的。对于一个分数 \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}
45
19

45
19

45
19

45
19

45
19

=
3
1

+
12
1

+
180
1

=
3
1

+
15
1

+
45
1

=
3
1

+
18
1

+
30
1

=
4
1

+
6
1

+
180
1

=
5
1

+
6
1

+
18
1

最好的是最后一种,因为 \dfrac{1}{18}
18
1

比 \dfrac{1}{180}, \dfrac{1}{45}, \dfrac{1}{30}
180
1

,
45
1

,
30
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}
211
59

211
59

=
4
1

+
36
1

+
633
1

+
3798
1

=
6
1

+
9
1

+
633
1

+
3798
1

由于方法一与方法二中,最小的分数相同,因此二者均是最优解。

给出 a,ba,b,编程计算最好的表达方式。保证最优解满足:最小的分数 \ge \cfrac{1}{10^7}≥
10
7

1

输入格式

一行两个整数,分别为 aa 和 bb 的值。

输出格式

输出若干个数,自小到大排列,依次是单位分数的分母。

输入输出样例

输入 #1复制
19 45
输出 #1复制
5 6 18

说明/提示

1 \lt a \lt b \lt 10001<a<b<1000

上代码:

#include <cstdio>
#include <cstring>
#include <cmath>

#define LL long long
#define MAXN 1010
#define max(x,y) (x > y ? x : y)

LL a, b, depth;
bool flag;
LL temp[MAXN], ans[MAXN];	// 分别记录当前答案与最终答案。

LL gcd (LL x, LL y) {
    return (!y ? x : gcd (y, x % y));
}	// 求最大公约数。

void dfs (LL newa, LL newb, LL step) {
    if (step + 1 == depth) {
        if (newa == 1) {
            temp[step + 1] = newb;
            flag = true; 
            if (temp[depth] < ans[depth] || !ans[depth]) {
                memcpy (ans, temp, sizeof (temp));
            }
        }

        return ;
    }

    LL first = newb % newa ? newb / newa + 1 : newb / newa;
    for (LL i = max (temp[step] + 1, first); i <= ceil (newb / newa) * (depth - step); i++) {
        temp[step + 1] = i;
        LL nxta, nxtb, g;
        nxta = newa * i - newb;
        nxtb = newb * i;
        g = gcd (nxta, nxtb);
        dfs (nxta / g, nxtb / g, step + 1);
    }
}	// 搜索主体。

int main (void) {

    scanf ("%d %d", &a, &b);
    LL g = gcd (a, b);
    temp[0] = 1;

    for (depth = 1; ; depth++) {
        dfs (a / g, b / g, 0);
        if (flag) { break ; }
    }
    for (int i = 1; i <= depth; i++) {
        printf ("%d ", ans[i]);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值