第1部分 基礎算法(提高篇)--第3章 深搜的剪枝技巧-1444:埃及分數

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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章