迭代加深搜索(埃及分数)

迭代加深:对于可以用回溯法求解但解答树的深度没有明显上限的题目,可以考虑使用迭代加深搜索。(dfs+剪枝)
如果可以设计出乐观估价函数,则迭代加深搜索成了IDA*算法

深度递增,仿广搜,限定下界的深搜;迭代加深,剪枝。
已埃及分数为例:
题目:
http://acm.nefu.edu.cn/JudgeOnline/problemshow.php?problem_id=358

题意:某真分数,需要将其化简为最少的若干特殊真分数之和,要输出这个序列(序列按递增序)。如果有不同的方案,则分数个数相同的情况下使最大的分母最小。若还相同,则使次大的分母最大……以此类推。如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的。对于一个分数a/b,表示方法有很多种,但是哪种最好呢? 首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。

#include<iostream>
#include<stdio.h>
#include<cstring>
#define LL long long
using namespace std;

int ans[1000];
int v[1000];
int maxd;
int ok = 0;
int a, b;

int gcd(int a, int b){
    return b? gcd(b, a%b):a;
}

bool better(int d)
{
    for(int i = d; i >= 0; i--)
        if(v[i] != ans[i])
        //两种情况,1:ans[i]为-1(未更新)则更新。
        //2:当前分数比目前最优分数大(优)则更新
            return ans[i] == -1 || v[i] < ans[i];
    return false;
}

int get_first(LL a, LL b)
{
    LL c = b / a;

    if( b % a  ) c+=1;
    return c;
}

LL max(LL a, LL b){ return a>b ? a : b; }

bool dfs(int d, int from, LL aa, LL bb)
{
    if(d == maxd)
    {
        if( bb%aa != 0 ) return false;
        v[d] = bb / aa;
        if(better(d)) memcpy(ans, v, sizeof(LL) * (d+1) );
        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,则无解,break;称为“剪枝”
        v[d] = i;
        LL b2 = bb * i;
        LL a2 = aa * i - bb;
        LL g = gcd(a2, b2); //便于约分
        if(dfs(d+1, i+1, a2 / g, b2 / g)) ok = true;
    }

    return ok;
}


int main()
{
    cin>>a>>b;
    //cout<<get_first(a, b)<<endl;

    for(maxd = 1;; maxd++)
    {
        memset(ans, -1, sizeof(ans));
        if(dfs (0, get_first(a, b), a, b) )
        {
            ok = 1; break;
        }
    }

    for(int i = 0; ans[i] != -1; i++)
    {
        printf(" 1/%d", ans[i]);
    }
}

你可能感兴趣的:(算法)