描述
在古埃及,人们使用单位分数的和(形如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
思路:
bfs?感觉内存可能撑不住,那就dfs吧。用结构题储存分数(分子,分母),对每个要搜索的分数都设定一个范围,首先减数要小于被减数 a/b> 1/i 根据条件往后的分母都要大于之前的分母且满足层数小于等于最少层数可知如果 所剩层数/i<当前被减分数,则不可能会得到更优的结果,这样以来每一层减数的分母范围就有了,当a==1时进行最佳值判定,如果a!=1&&当前层数大于等于最少层数或者当前分母大于最值最后一层的分母则直接剪掉这部分分支
当我自信提交时 TLE。。。
我输出了一下每层的i后发现一直不停的输出。。。
通过百度后了解到了迭代加深搜这个算法,每次限定搜索层数,虽然会重复搜索,但是重复比起下一层要搜索的要少的多
此题通过枚举最少深度,来进行搜索
代码:
#include<stdio.h>
#include<queue>
#define ll long long
using namespace std;
ll re[1005],cnt_r,tmp[1005];
bool flag;
struct node
{
ll fz,fm;
};
ll gcd(ll a,ll b)
{
a%=b;
while(a)
{
b%=a;
if(!b)return a;
a%=b;
}
return b;
}
node hj(node a)
{
ll tmp=gcd(a.fz,a.fm);
a.fm/=tmp;
a.fz/=tmp;
return a;
}
node del(node a,ll fm)
{
ll gd;
if(a.fm>fm)gd=gcd(a.fm,fm);
else gd=gcd(fm,a.fm);
gd=a.fm/gd*fm;
a.fz=gd/a.fm*a.fz-gd/fm;
a.fm=gd;
return hj(a);
}
ll mx(ll a,ll b)
{
return a>b?a:b;
}
void dfs(node a,ll deep,ll st)
{
if(a.fz==1&&a.fm!=st-1)
{
tmp[1]=a.fm;
if(!flag||re[1]>tmp[1])
{
for(int i=1;i<=cnt_r;i++)re[i]=tmp[i];
}
flag=1;
return ;
}
if(deep==1)return ;
for(ll i=mx(st,a.fm/a.fz+1);;i++)
{
if(a.fz*i>deep*a.fm||flag&&i>=re[1])return ;
if(a.fz*i>a.fm){
tmp[deep]=i;
dfs(del(a,i),deep-1,i+1);}
}
}
int main()
{
node a;
scanf("%lld%lld",&a.fz,&a.fm);
a=hj(a);
for(int i=1;;i++)
{
flag=false;
cnt_r=i;
dfs(a,i,2);
if(flag)
break;
}
for(int i=cnt_r;i;i--)
printf("%lld%c",re[i],i>1?' ':'\n');
return 0;
}
若有什么错误,欢迎指正^ _ ^ 。