ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【ACWing】1120. 埃及分数

2021-04-18 15:29:37  阅读:267  来源: 互联网

标签:分数 frac 19 1120 45 枚举 int depth ACWing


题目地址:

https://www.acwing.com/problem/content/1122/

在古埃及,人们使用单位分数的和(形如 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 19 45 = 1 3 + 1 15 + 1 45 19 45 = 1 3 + 1 18 + 1 30 19 45 = 1 4 + 1 6 + 1 180 19 45 = 1 5 + 1 6 + 1 18 \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} 4519​=31​+121​+1801​4519​=31​+151​+451​4519​=31​+181​+301​4519​=41​+61​+1801​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 59 211 = 1 6 + 1 9 + 1 633 + 1 3798 \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} 21159​=41​+361​+6331​+37981​21159​=61​+91​+6331​+37981​由于方法一与方法二中,最小的分数相同,因此二者均是最优解。给出 a , b a,b a,b,编程计算最好的表达方式。保证最优解满足:最小的分数 ≥ 1 1 0 7 ≥\frac{1}{10^7} ≥1071​。

输入格式:
一行两个整数,分别为 a a a和 b b b的值。

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

数据范围:
0 < a < b < 1000 0<a<b<1000 0<a<b<1000

思路是迭代加深。其实就是直接枚举每个单位分数的分母,找到最优答案即可。在分解 a b \frac{a}{b} ba​的时候,如果不限制深度,容易走到非常深的位置还不一定能找到最优解,所以最好的办法还是迭代加深。对于DFS每一层,设当前深度是 d d d,就枚举第 d d d个数的分母可以取哪些数。我们可以逐层按照分母从小到大枚举,这样第 d d d个数的分母首先要严格大于上一层枚举的分母。其次,设当前层还需要凑出的分数是 a b \frac{a}{b} ba​,先对其约分,如果 a = 1 a=1 a=1了,那么就找到了一个解,查看其是否更优(即其最大分母是不是小于之前找到的解的最大分母),如果更优则覆盖之前的解(当然如果之前没找到解,那么当前解直接覆盖);否则开始枚举一个分数,设当前枚举的数是 1 x \frac{1}{x} x1​,首先有 1 x < a b \frac{1}{x}<\frac{a}{b} x1​<ba​,所以有 x > b a x>\frac{b}{a} x>ab​,由于 a ≠ 1 a\ne 1 a​=1,所以其等价于 x ≥ ⌊ b a ⌋ + 1 x\ge \lfloor \frac{b}{a}\rfloor + 1 x≥⌊ab​⌋+1;此外,由于是按照分母从小到大枚举的,设当前DFS设定的最大深度是 D D D,那么还需要枚举 D − d + 1 D-d+1 D−d+1个数(包括本层枚举的数),所以有 ( D − d + 1 ) 1 x > a b (D-d+1)\frac{1}{x}>\frac{a}{b} (D−d+1)x1​>ba​,即 x ≤ ⌊ b a ( D − d + 1 ) ⌋ x\le\lfloor\frac{b}{a}(D-d+1)\rfloor x≤⌊ab​(D−d+1)⌋。所以只需枚举这个范围内的数即可。代码如下:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 1e7;
int res[N], tmp[N];

long gcd(long a, long b) {
    return b ? gcd(b, a % b) : a;
}

bool dfs(int u, long a, long b, int depth, int max_depth) {
    if (depth == max_depth) {
        if (a == 1) {
        	// 如果分母大于了10^7,则与题目给出的数据范围不符,直接返回false
            if (b > 1e7) return false;

            tmp[depth - 1] = (int) b;
            if (!res[depth - 1] || b < res[depth - 1]) {
                memcpy(res, tmp, depth * (sizeof(int)));
            }

            return true;
        }

        return false;
    }

    bool found = false;
    // 枚举当前层的分数的分母
    for (int i = max(u, (int) (b / a) + 1); i <= b / a * (max_depth - depth + 1); i++) {
    	// 用long以防溢出
        long nx = a * i - b, ny = b * i;
        // 做约分
        long g = gcd(nx, ny);
        nx /= g, ny /= g;
        // 存储一下当前选择
        tmp[depth - 1] = i;
        if (dfs(u + 1, nx, ny, depth + 1, max_depth)) found = true;
    }

    return found;
}

int main() {
    int a, b;
    scanf("%d%d", &a, &b);

    int g = (int) gcd(a, b);
    a /= g, b /= g;

    int max_depth = 1;
    while (!dfs(2, a, b, 1, max_depth))
        max_depth++;

    for (int i = 0; i < max_depth; i++)
        printf("%d ", res[i]);
    printf("\n");

    return 0;
}

时间复杂度指数级,空间取决于具体输入的搜索深度。

标签:分数,frac,19,1120,45,枚举,int,depth,ACWing
来源: https://blog.csdn.net/qq_46105170/article/details/115829751

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有