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

时间:2019-08-14
本文章向大家介绍UVA12558 埃及分数 Egyptian Fractions (HARD version) 笔记,主要包括UVA12558 埃及分数 Egyptian Fractions (HARD version) 笔记使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

笔记就 懒得搞得有多好看了 自己看的顺就行

贴个luogu链接 uva比较慢 UVA12558 埃及分数 Egyptian Fractions (HARD version)

一开始看着紫书写的 就是添加了个约束条件 现在理解了之后搞一个

 

题目是搜索  考虑BFS 状态数太多 一次要向不知道数量个状态转移 不行

       考虑DFS 解决了状态数过多的问题 但是深度太深了 也不行

  所以就IDDFS解决 每次把a/b减去一个1/c 直到到达深度限制且最后减去的为埃及分数并且分母不受限

代码

#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;

using std::cin;
using std::cout;
using std::endl;

std::map<ll, int>map;  //利用map来判断能不能用
ll ans[105], tmp[105];  //存答案

ll gcd(ll a, ll b) {if(a < b) std::swap(a, b); return b == 0 ? a : gcd(b, a % b);}  
//不知道static_cast和(int)()有什么区别 不过看着很吊就是了
ll get_first(ll a, ll b) {return static_cast<int>(b / a) + 1;}  //得到1/c <= a/b的c的最大值 由1/c <= a/b可推导出b <= a * c 进而推导出b / a <= c

bool check(int dep) {  //判断最优解
    for(int i = dep; i >= 0; i--) 
        if(ans[i] != tmp[i]) return ans[i] == -1 || ans[i] > tmp[i];  //要求的是分母最小 ans[i] == -1判断
    return false;
}

void replace(int dep) {for(int i = 0; i <= dep; i++) ans[i] = tmp[i];}

bool IDDFS(int dep_lim, int dep, ll up, ll down, ll min) {  //dep_lim为深度限制 dep为当前深度 up为剩下的分子 down为剩下的分母
    bool flag = false;  //因为是最优解 而第一个搜到的不一定是最优解 所以不能够搜到直接return
    if(dep >= dep_lim) {  //深度大于等于限制是就需要判断了
        if(down % up) return false;  //因为埃及分数的分子只能为1(然而那题题面没写)所以如果分子不是1就不是答案
        tmp[dep] = down / up;  //得到分母 存入答案
        if(map.count(tmp[dep])) return false;  //如果分母不能用就不是
        if(check(dep)) replace(dep);  //更新最优解
        return true;
    }
    for(int i = std::max(min, get_first(up, down)); ; i++) {  //因为最后得出的那个的分母是递增的 所以遍历下界的第一个条件为上次的分母,也就是min 另外一个条件为1/c <= a/b时c的最小值,因为如果1/c > a/b,那么就不会有结果
        if(down * (dep_lim - dep + 1) <= up * i) break;  //如果剩下几个全为1/i,加起来也不超过up/down就直接break,因为随着i的增大1/i只会越来越小,由(dep_lim - dep + 1) * (1 / i) < up / down可推导出
        if(map.count(i)) continue;  //如果i为受限的分母 就不能选
        tmp[dep] = i;  //存答案
        ll b = i * down;  //由up/down - 1/i = a/b可得出 up/down - 1/i = a/b --> (up * i)/(down * i) - down/(i * down) = a/b --> a = up * i - down, b = down * i
        ll a = up * i - down;
        ll g = gcd(a, b);  //gcd
        if(IDDFS(dep_lim, dep + 1, a/g, b/g, i + 1)) flag = true;  
    }
    return flag;
}

int main() {
    int t;
    scanf("%d", &t);
    int it = 1;
    while(t--) {
        int a, b, k;
        memset(ans, -1, sizeof(ans));
        memset(tmp, -1, sizeof(tmp));
        map.clear();
        scanf("%d%d%d", &a, &b, &k);
        for(int i = 0; i < k; i++) {
            ll tmp;
            scanf("%lld", &tmp);
            map[tmp] = 1;
        }
        int dep = 0;
        while(1) {
            if(IDDFS(dep, 0, a, b, get_first(a, b))) break;
            dep++;
        }
        printf("Case %d: %d/%d=", it++, a, b);
        for(int i = 0; i < dep; i++) printf("1/%d+", ans[i]);
        printf("1/%d\n", ans[dep]);
    }
    system("pause");//上交oj时记得注释或删除
    return 0;
}

不知道cnblogs怎么用latex就没用 一些细节也都标出来了 反正也是给自己看

#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;

using std::cin;
using std::cout;
using std::endl;

std::map<ll, int>map;
ll ans[105], tmp[105];

ll gcd(ll a, ll b) {if(a < b) std::swap(a, b); return b == 0 ? a : gcd(b, a % b);}

ll get_first(ll a, ll b) {return static_cast<int>(b / a) + 1;}

bool check(int dep) {
    for(int i = dep; i >= 0; i--) 
        if(ans[i] != tmp[i]) return ans[i] == -1 || ans[i] > tmp[i];
    return false;
}

void replace(int dep) {for(int i = 0; i <= dep; i++) ans[i] = tmp[i];}

bool IDDFS(int dep_lim, int dep, ll up, ll down, ll min) {
    bool flag = false;
    if(dep >= dep_lim) {
        if(down % up) return false;
        tmp[dep] = down / up;
        if(map.count(tmp[dep])) return false;
        if(check(dep)) replace(dep);
        return true;
    }
    for(int i = std::max(min, get_first(up, down)); ; i++) {
        if(down * (dep_lim - dep + 1) <= up * i) break;
        if(map.count(i)) continue;
        tmp[dep] = i;
        ll b = i * down;
        ll a = up * i - down;
        ll g = gcd(a, b);
        if(IDDFS(dep_lim, dep + 1, a, b, i + 1)) flag = true;
    }
    return flag;
}

int main() {
    int t;
    scanf("%d", &t);
    int it = 1;
    while(t--) {
        int a, b, k;
        memset(ans, -1, sizeof(ans));
        memset(tmp, -1, sizeof(tmp));
        map.clear();
        scanf("%d%d%d", &a, &b, &k);
        for(int i = 0; i < k; i++) {
            ll tmp;
            scanf("%lld", &tmp);
            map[tmp] = 1;
        }
        int dep = 0;
        while(1) {
            if(IDDFS(dep, 0, a, b, get_first(a, b))) break;
            dep++;
        }
        printf("Case %d: %d/%d=", it++, a, b);
        for(int i = 0; i < dep; i++) printf("1/%d+", ans[i]);
        printf("1/%d\n", ans[dep]);
    }
    //system("pause");//上交oj时记得注释或删除
    retu

$flag 上一页 下一页