埃及分数
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[N],d[N];
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;
}