【WOJ 1608】埃及分数

【题目】

题目描述:

任何一个分数都能才成若干个单位分数(形如 1 / a 1/a 1/a 的, a a a 是自然数)的和。

对于一个分数 a / b a/b a/b,表示方法有很多种,但是哪种最好呢?

首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好,如果还是相同,那么第二小的分数越大越好,依次类推下去。

例如对于 19 / 45 19/45 19/45,下列方法都是合法的

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/18 1/18 1 / 180 1/180 1/180 1 / 45 1/45 1/45 1 / 30 1/30 1/30 1 / 180 1/180 1/180 都大。

现在给出 a , b ( 0 &lt; a &lt; b &lt; 1000 ) a,b(0&lt;a&lt;b&lt;1000) a,b(0<a<b<1000),求最好的表达方式。

输入格式:

输入一行,用两个整数表示 a a a b b b

输出格式:

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

样例数据:

输入
19 45

样例输出
5 6 18


【分析】

一道迭代加深的题

依旧是不断增加 d f s dfs dfs 的深度,对于每个深度都判断能否找到答案,能就输出,不然就继续 d f s dfs dfs

这里解释一些代码中的细节吧

  1. 对于一个分数 a / b a/b a/b,使得 1 / c ≤ a / b 1/c≤a/b 1/ca/b 的最小的 c c c b / a + 1 b/a+1 b/a+1,所以要从 b / a + 1 b/a+1 b/a+1 开始枚举
  2. 代码中的剪枝就是如果枚举到 i i i,后面的分数肯定都小于 1 / i 1/i 1/i,如果 ( h − d e p + 1 ) / i ≤ a / b (h-dep+1)/i≤a/b (hdep+1)/ia/b,就肯定不行,直接 b r e a k break break

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10005
#define ll long long
using namespace std;
int h;
ll ans[N],temp[N];
bool better()
{
	for(int i=h;i>=0;--i)
	  if(ans[i]!=temp[i])
	    return ans[i]==-1||ans[i]>temp[i];
	return false;
}
bool dfs(int dep,int start,ll a,ll b)
{
	if(dep==h)
	{
		if(b%a)  return false;
		temp[dep]=b/a;
		if(better())  memcpy(ans,temp,sizeof(ans));
		return true;
	}
	bool flag=false;
	start=max((ll)start,b/a+1);
	for(int i=start;;++i)
	{
		if(b*(h-dep+1)<=a*i)  break;
		temp[dep]=i;
		ll x=a*i-b,y=b*i,gcd=__gcd(x,y);
		if(dfs(dep+1,i+1,x/gcd,y/gcd))  flag=true;
	}
	return flag;
}
int main()
{
	int a,b,i;
	scanf("%d%d",&a,&b);
	for(h=1;;++h)
	{
		memset(ans,-1,sizeof(ans));
		if(dfs(0,b/a+1,a,b))  break;
	}
	for(i=0;i<=h;++i)
	  printf("%lld ",ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值