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

Posted Neord

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vijos 1308 埃及分数(迭代加深搜索)相关的知识,希望对你有一定的参考价值。

题意:

输入a、b, 求a/b 可以由多少个埃及分数组成。

埃及分数是形如1/a , a是自然数的分数。

如2/3 = 1/2 + 1/6, 但埃及分数中不允许有相同的 ,如不可以2/3 = 1/3 + 1/3.

求出可以表达a/b个数最少埃及分数方案, 如果个数相同则选取最小的分数最大。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
int maxd;
long long v[1234],ans[1234];
bool better(int d){
    for(int i = d; i >= 0; i--){
        if(v[i] != ans[i]){ //如果这一层没有标记, 或者标记的数小于传入的v[i], 说明当前为更优解
            return ans[i] == -1 || v[i] < ans[i];
        }
        return false;
    }
}
//求满足 1/c <= a/b 最大的1/c, 即最小的c
inline int get_first(LL a,LL b){
    return b/a+1;
}
//当前深度为d, 分母不能小于from, 分数之和为aa, bb
bool dfs(int d, int from, LL aa, LL bb){

    if( d == maxd){
        if(bb % aa) return false;
        v[d] = bb / aa;
        if(better(d)) memcpy(ans, v , sizeof(v));
        return true;
    }

  bool ok = false;
  from = max(from, get_first(aa, bb)); // 如果上一次递归的from不符合aa/bb最小的分母, 则取get_first(aa,bb)

  for(int i = from;  ; i++) {
    // 剪枝:如果剩下的maxd+1-d个分数全部都是1/i,加起来仍然不超过aa/bb,则无解
    if(bb * (maxd+1-d) <= i * aa) break;
    v[d] = i;
    // 计算aa/bb - 1/i,设结果为a2/b2
    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(){
    int a, b;
    scanf("%d %d", &a, &b);
    for(maxd = 1; ;maxd++){ //这里可以做一些限制, 层数上限不一定为infinite
        memset(ans, -1, sizeof(ans));
        if(dfs(0,get_first(a,b),a,b)) {
            break;
        }
    }
    for(int i = 0; i <= maxd; i++) printf("%lld ", ans[i]);
}

 

以上是关于Vijos 1308 埃及分数(迭代加深搜索)的主要内容,如果未能解决你的问题,请参考以下文章

[题解]「一本通 1.3 练习 1」埃及分数

埃及分数,迭代加深

UVA12558 Egyptian Fractions (HARD version) (埃及分数)

迭代加深,埃及分数

埃及分数问题

埃及分数