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

来源:互联网 发布:二十四节气壁纸软件 编辑:程序博客网 时间:2024/05/20 09:43

题目链接: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;}
0 0