您的位置:首页 > 其它

NEFU 358 埃及分数(迭代加深,数学)

2016-08-05 15:29 330 查看


埃及分数


Problem:358


Time Limit:1000ms


Memory Limit:65536K


Description

对于每一个非负有理数,我们知道它一定能划归成某些特殊真分数之和,特殊真分数要满足它们的分子为1,但是我们知道,对于无穷级数1/2+1/3+1/4…。虽然,它是发散的,但是改级数增长得极为缓慢,例如到了数百万之后,和也在18~19左右。
若干年来,不断有人宣称发现了该级数的特殊性质,这些都对这个问题的研究起到了深远的影响。
你的任务来了,要求给你个真分数,你需要将其化简为最少的若干特殊真分数之和,你要输出这个序列(序列按递增序)。
如果有不同的方案,则分数个数相同的情况下使最大的分母最小。若还相同,则使次大的分母最大……以此类推。
如: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
最好的是最后一种,因为18 比180, 45, 30,都小。



Input

多组数据输入.
每组输入一行,a,b,(0<=a<b<=1000)表示要化简的数为a/b



Output

输出一个算式,格式见样例。每个+、=号两边都没空格。



Sample Input

3 7



Sample Output

3/7=1/4+1/7+1/28


题意:中文题不解释

思路:第一次做迭代加深...真难啊。

迭代加深去枚举拆出来几个子分数

当可以达到b%a==0的时候满足条件

题目似乎有点问题,我只判断了最大的最小就过了。

注意每一次枚举的下界是b/a,因为1/(b-a-1)大于a/b了

上界是(dep-k+1)*b/a,这里是假设后面的dep-k+1个数都跟这个数相等会等于这个,但是题目说了不能相等并且并且后面的分数分母比当前大,所以这是上界

还注意一点剪枝即可

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 10
int ans
,d
;
int dep,flag;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
void dfs(int a,int b,int k)
{
if(k>dep) return;
if(b%a==0&&b/a>d[k-1])
{
d[k]=b/a;
if(!flag||d[k]<ans[k])
memcpy(ans,d,sizeof(d));
flag=1;
return;
}
int s=b/a;
if(s<d[k-1]) s=d[k-1]+1;
int t=(dep-k+1)*b/a;
if(flag&&t>=ans[dep]) t=ans[dep]-1;
for(int i=s;i<=t;i++)
{
d[k]=i;
int m=gcd(a*i-b,b*i);
dfs((a*i-b)/m,b*i/m,k+1);
}
}
void solve(int a,int b)
{
d[0]=1;
flag=0;
for(dep=1;dep<=N;dep++)
{
dfs(a,b,1);
if(flag)
{
for(int i=1;i<dep;i++)
printf("1/%d+",ans[i]);
printf("1/%d\n",ans[dep]);
break;
}
}
}
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
printf("%d/%d=",n,m);
solve(n,m);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: