题目地址
大家可自行注册账号,在右上角,或者在jzoj提交
题目描述
输入
一行两个整数,分别为 a 和 b 的值。
输出
输出若干个数,自小到大排列,依次是单位分数的分母。
样例输入
19 45
样例输出
5 6 18
提示
0<a<b<1000
解法
妥妥的深搜,
- 我们dfs的状态就定为当前剩余分数的分子和分母,以及当前分数数量
- 再进行枚举分数数量,进行深搜
详解看代码
#include<bits/stdc++.h>
#define N 1000
using namespace std;
long long ans[N],s[N],mo,ch;
//ans记录答案,s用于更新
//搜索时用s记录
int dep;
long long gcd(long long a,long long b)
{return !b?a:gcd(b,a%b);}//GCD,最大公约数
void outp()//更新答案
{
if(ans[dep]>s[dep])
for(int i=1;i<=dep;i++)
ans[i]=s[i];
}
void dfs(long long x,long long y,int d)
{//d是分数个数
long long a,b,i,w;
if(d==dep)
{
s[d]=y;
//x==1说明已分解为埃及分数
if((x==1)&&(s[d]>s[d-1]))outp();
return;//^更新答案
}
for(i=max(s[d-1]+1,y/x+1);i<(dep-d+1)*y/x;i++)
//起点:保证最大 终点:以后的分母都要比目前的大,所以大于(dep-d+1)*y/x的话,相加只能小于原分数
{ //i枚举分母
//a是减去1/i后的分子
//b是减去1/i后的分母
a=(x*i-y);
b=(y*i);
w=gcd(a,b);//原分数是x/y,减去1/i后是(x*i-y)/(y*i)=a/b;
a/=w;//化为最简
b/=w;//化为最简
s[d]=i;
dfs(a,b,d+1);
}
}
int main()
{
int i=0,j;
scanf("%lld%lld",&ch,&mo);
i=gcd(ch,mo);
ch/=i;
mo/=i;
for(dep=2;;dep++)//枚举个数
{//deep记录由几个分数组成
ans[1]=0;
s[0]=0;
ans[dep]=2000000000;
dfs(ch,mo,1);
if(ans[1]!=0)break;
}
for (j=1;j<=dep;j++) printf("%lld ",ans[j]);
return 0;
}