迭代加深搜索 (IDA*)

       迭代加深搜索: 从小到大枚举深度 maxd, 每次执行只考虑深度不超过maxd的结点。这样,只要解得深度有限,则一定可以在有限的时间内枚举到(一定要有解哈)

       如果可以设计出一个乐观估价函数,预测从当前结点至少还需要扩展几层结点才有可能得到解,则迭代加深搜索变成了IDA*算法

经典的埃及分数问题:

       在古埃及,人们使用单位分数的和(1/a, a为自然数),表示有理数、例如2/3 = 1/2 + 1/6,但   2/3 = 1/3 + 1/3是不允许的,因为加数不允许相同

对于一个分数a/b,表示方法有很多种,其中加数少的比加数多的好,如果加数个数相同,则最小的分数越大越好。例如, 19/45 = 1/5 + 1/6 + 1/8就是最优方案。

输入: 495 499

输出:Case 1: 495/499 = 1/2 + 1/5 + 1/6 + 1/8 + 1/3992 + 1/14970


代码:

//经典的埃及分数
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

int maxd;
int ans[1000];
int v[1000];
int a, b;

int gcd(LL a, LL b)
{
    if(b == 0) return a;
    else return gcd(b, a%b);
}

int get_first(int a, int b) //找到满足 1/c <= a/b 的最小的c 也就是找到满足这个条件的最大的1/c
{
    int c = 1;
    while(b > a*c) c++;
    return c;
}

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

bool dfs(int d, int from, LL aa, LL bb) //当前深度为d, 分母不能小于from, 分数之和恰好是aa/bb
{
    if(d == maxd)
    {
        if(bb % aa) return false;
        v[d] = bb / aa;
        if(better) memcpy(ans, v, sizeof(LL)*(d+1)); //把v里面的东西拷贝到ans里面
        return true;
    }
    bool ok = false;
    from = max(from, get_first(aa, bb)); //当前分母或者是
    for(int i = from;  ; i++)
    {
        if(bb * (maxd+1-d) <= i * aa) break;   // 函数剪枝(maxd+1-d) * (1/i) <= (aa/bb)
        v[d] = i;
        LL b2 = bb * i;
        LL a2 = aa * i - bb;  //新的分数为 (aa/bb - 1/i) = (aa - bb*i)/(bb*i);
        LL g = gcd(a2, b2);
        if(dfs(d+1, i+1, a2/g, b2/g))
            ok = true;
    }
    return ok;
}


int main()
{
    int ok = 0;
    while(scanf("%d %d", &a, &b))
    {
        for(maxd = 1; ; maxd++)
        {
           memset(ans, -1, sizeof(ans));
           if(dfs(0, get_first(a, b), a, b))
           {
               ok = 1; break;
           }
        }
        printf("%d/%d = ", a, b);
        for(int i = 0; ; i++)
        {
            if(ans[i] > 0)
                printf("%s1/%d", i == 0 ? "" : "+", ans[i]);
            else
            {printf("\n"); break;}
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值