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