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]);
}
原文地址:https://www.cnblogs.com/Jadon97/p/8320677.html