CODE[VS] 1288 埃及分数

题目描述 Description

在古埃及,人们使用单位分数的和(形如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),编程计算最好的表达方式。

输入描述 Input Description

a b

输出描述 Output Description

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

样例输入 Sample Input

19 45

样例输出 Sample Output

5 6 18

数据范围及提示 Data Size & Hint
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

第一次用memcpy,调试到吐血……然后测出来用法是 memcpy(被赋值数组,被复制数组,长度),可以+1。

然后,也是第一次用迭代加深搜索,因为没有回溯检查了两个小时……

分子分母的转化还是很巧妙的,具体看代码~

还有每次搜索可以限制分母i的值,大于已算值,因为限制总分数个数所以也要小于现在的分母除以分子再除以个数~

 

 

#include<cstdio>
#include<cstring>

int a,b,tot[1001],ans[1001];

int gcd(int u,int v)
{
	return v ? gcd(v,u%v):u;
}

void dfs(int u,int v,int aa,int bb)
{
	if(u==v) return;
	if(bb%aa==0 && bb/aa>tot[tot[0]] && (ans[0]<=0 || ans[ans[0]]>(bb/aa)))  //找到后返回(条件:没有原数或比原数末位小)
	{
		memcpy(ans,tot,sizeof(tot));
		ans[++ans[0]]=bb/aa;
		return;
	}
	int i=bb/aa-1,j=(u-v)*(bb/aa);
	if(i<=tot[tot[0]]) i=tot[tot[0]];
	while(++i<=j)  //极限为j
	{
		if(ans[0]>0 && ans[ans[0]]<=i) return;
		int k=gcd(i,bb),z=i/k,x=bb*z,y=aa*z-bb/k;
		if(y<0) continue;
		tot[++tot[0]]=i;
		if(!y)
		{
			memcpy(ans,tot,sizeof(tot));
			tot[0]--;return;
		}
		dfs(u,v+1,y,x);
		tot[0]--;  //回溯! 
	}
}

int main()
{
	scanf("%d%d",&a,&b);
	for(int i=1;i<=100;i++)
	{
		dfs(i,0,a,b);
		if(ans[0]) break;
	}
	for(int i=1;i<=ans[0];i++) printf("%d ",ans[i]);
	return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值