1444:埃及分數
時間限制: 1000 ms 內存限制: 65536 KB
提交數: 949 通過數: 334
【題目描述】
在古埃及,人們使用單位分數的和(形如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
思路:
某個真分數的分子爲a,分母爲b;
把b除以a的商部分加1後的值作爲埃及分數的某一個分母c;
將a乘以c再減去b,作爲新的a;
將b乘以c,得到新的b;
如果a大於1且能整除b,則最後一個分母爲b/a;算法結束;
或者,如果a等於1,則最後一個分母爲b;算法結束;
否則重複上面的步驟。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
LL s[7], cnt, ans[7], len = 10;
LL a, b, m_depth;
bool flag;
inline LL gcd(LL a, LL b){
if( !b )
return a;
return gcd(b, a%b);
}
inline void DFS(LL a, LL b, LL k){
if( k > m_depth )
return ;
if( b%a == 0 && b/a > s[k-1] ){
s[k] = b/a;
if( !flag || s[k] < ans[k] )
memcpy(ans,s,sizeof(s));
flag = 1;
return;
}
LL q = b/a;
if( q <= s[k-1] )
q = s[k-1]+1;
LL t = b*(m_depth-k+1)/a;
if( flag && t >= ans[m_depth] )
t = ans[m_depth]-1;
for(LL i = q; i <= t; i ++){
LL m = gcd(i*a-b, b*i);
s[k] = i;
DFS((i*a-b)/m,b*i/m,k+1);
}
}
int main(){
scanf("%lld%lld", &a, &b);
LL d = gcd(a,b);
a /= d;
b /= d;
for(m_depth = 1; m_depth <= 10; m_depth ++){
DFS(a, b, 0);
if( flag ){
printf("%lld", ans[0]);
for(int i = 1; i <= m_depth; i ++)
printf(" %lld", ans[i]);
break;
}
}
return 0;
}