1444 埃及分数(修正案)

在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数。如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的。对于一个分数a/b,表示方法有很多种,但是哪种最好呢?首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。

如: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.

最好的是最后一种,因为1/18比1/180,1/45,1/30,1/180都大。

给出a,b(0<a<b<1000),编程计算最好的表达方式。

【输入】

输入:a b

【输出】

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

【输入样例】

19 45

【输出样例】

5 6 18
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
const int N = 200 + 5;
using namespace std;
long long maxDeep;
long long temp[N];//
long long res[N];//构成目标数的单位分数
long long GCD(long long a, long long b) {
    return b == 0 ? a : GCD(b, a % b);
}
long long getLimit(long long x, long long y) {
    for (long long i = 2;; i++)//求比目标数小的最大的单位分数
        if (y < x*i)//求不比目标小的最大单位分数(1/i<x/y化简的结果)
            return i;
}
bool judge(long long step) {
    if (res[step] == -1)//第一次运行,把temp的数值输送到res中
        return true;
    else if (temp[step] > res[step])
        return false;
    else if (temp[step] < res[step])//当大分数分母比原来小进行更新
        return true;
    else
        return false;
}
bool dfs(long long step, long long minn, long long x, long long y) {//step:已经构成step个单位分数? minn:   x: 目标分子 y:目标分母
    if (step == maxDeep) {//已经构成maxdeep多个单位分数
        if (y % x!=0)//判断x和y是否能够从单位分数,如果不能,返回false
            return false;//无法构成
        else {
            temp[step] = y / x;//temp[step]变成这个这个单位分数的分母
            if (judge(step))//存在更优解,更新答案
                memcpy(res, temp, sizeof(temp));//把这个临时数据放入res中
            return true;//返回值为真
        }
    }
    minn = max(minn, getLimit(x, y));//找到最大不小于目标的单位分数的分母
    bool flag = false;//建立一个标志位,为false
    for (long long i = minn;; i++)//从下限开始循环,往上遍历,是单位分数的分母互不相等且从小到大排列,以防重复或遗漏 
    {
        if ((maxDeep - step + 1) * y <= x * i)//可行性剪枝,相当于((maxDeep-step+1)*(1/i)<=x/y)也就是说当maxdeep个最大不小于目标的单位分数相乘比目标还要小,那么肯定不可能,直接退出循环
            break;
        temp[step] = i;//能够成目标分数,所以temp[step]为构成目标分数的单位分数的其中一个分母
        long long ny = y * i;//原目标减去temp[step]的分母
        long long nx = x * i - y;//原目标减去temp[step]的分子
        long long gcd = GCD(nx, ny);//找出分子和分母的最大公约数,以便化简
        if (dfs(step + 1, minn + 1, nx / gcd, ny / gcd))//搜索成功可以构成目标分数,返回值为真
            flag = true;
    }
    return flag;
}
int main() {
    long long n, m;
    scanf_s("%lld%lld", &n, &m);// 分子  分母
    for (maxDeep = 1;; maxDeep++) {//有maxdeep个单位分数构成目标数字
        long long limit = getLimit(n, m);//比目标小的单位分数
        memset(temp, 0, sizeof(temp));//清0
        memset(res, -1, sizeof(res));//变成-1,变成其他值也行,不一定是-1
        if (dfs(0, limit, n, m))//找到第一个可行解即退出,进行搜索
            break;
    }
    for (long long i = 0; i <= maxDeep; i++)
        printf("%lld ", res[i]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值