UVa 12558:Egyptian Fractions (HARD version)(IDA*)

題目鏈接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=842&page=show_problem&problem=4003

題意:把a/b寫成不同的埃及分數之和,要求項數儘量小,在此前提下最小的分數儘量大,然後第二小的分數儘量大……另外有k(0k5) 個數不能用作分母。例如,k=0時5/121=1/33+1/121+1/363 ,不能使用33是最優解爲5/121=1/45+1/55+1/1089 。輸入保證2a<b876,gcd(a,b)=1 ,且會挑選比較容易求解的數據。(本段摘自《算法競賽入門經典(第2版)》)

分析:
       IDA*思想。在原來的埃及分數上加一些限制條件即可。

代碼:

#include <iostream>
#include <algorithm>
#include <fstream>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>

using namespace std;

const int maxn = 1000 + 5, INF = 1e8;

int T, k;
long long a, b;
long long x[10], add[maxn], ans[maxn];

long long gcd(long long x, long long y)
{
    return (y == 0) ? x : gcd(y, x % y);
}

long long get_first(long long x, long long y)
{
    return y / x + 1;
}

bool better(int deep)
{
    for (int i = deep; i >= 0; --i)
        if (ans[i] != add[i])
            return (ans[i] == -1 || add[i] < ans[i]);
    return false;
}

bool DFS(long long aa, long long bb, long long from, int deep, int limit)
{
    if (deep == limit)
    {
        if (bb % aa)
            return false;
        add[deep] = bb / aa;
        for (int i = 0; i < k; ++i)
            if (add[deep] == x[i])
                return false;
        if (better(deep))
            memcpy(ans, add, sizeof(long long) * (deep + 1));
        return true;
    }
    bool ok = false;
    for (long long i = max(get_first(aa, bb), from); ; ++i)
    {
        if (bb * (limit - deep + 1) <= i * aa)
            break;
        bool flag = true;
        for (int j = 0; j < k; ++j)
            if (i == x[j])
            {
                flag = false;
                break;
            }
        if (flag)
        {
            long long tmpa = aa * i - bb, tmpb = i * bb;
            long long tmp = gcd(tmpa, tmpb);
            tmpa /= tmp;
            tmpb /= tmp;
            add[deep] = i;
            if (DFS(tmpa, tmpb, i + 1, deep + 1, limit))
                ok = true;
        }
    }
    return ok;
}

int main()
{
    scanf("%d", &T);
    for (int C = 0; C < T; ++C)
    {
        memset(ans, -1, sizeof(ans));
        scanf("%lld%lld%d", &a, &b, &k);
        for (int i = 0; i < k; ++i)
            scanf("%d", &x[i]);
        printf("Case %d: ", C + 1);
        for (int maxd = 0; ; ++maxd)
            if (DFS(a, b, get_first(a, b), 0, maxd))
            {
                printf("%lld/%lld=", a, b);
                for (int i = 0; i <= maxd; ++i)
                    if (i < maxd)
                        printf("1/%lld+", ans[i]);
                    else
                        printf("1/%lld\n", ans[i]);
                break;
            }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章