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

时间: 2024-08-01 16:07:18

Vijos 1308 埃及分数(迭代加深搜索)的相关文章

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

#include<cstdio> #include<cmath> #include<cstring> using namespace std; typedef long long ll; ll depth,a,b,flag,ans[100005],nans[100005]; inline ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } inline void yuefen(ll &a,ll &b){ll eaa=g

【迭代加深搜索】埃及分数问题

谢谢阿苏~http://blog.csdn.net/urecvbnkuhbh_54245df/article/details/5856756 [迭代加深搜索(ID,iterative deepening)]:从小到大枚举上限maxd,每次执行只考虑深度不超过maxd的结点. ------对于可以用回溯法求解但解答树的深度没有明显上限的题目,可以考虑ID算法: ------优点:它主要是在递归搜索函数的开头判断当前搜索的深度是否大于预定义的最大搜索深度,如果大于,就退出这一层的搜索,如果不大于,就

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

题目链接:点击打开链接 题目描述: 在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数.如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的.对于一个分数a/b,表示方法有很多种,但是哪种最好呢?首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好. 如:19/45=1/3 + 1/12 + 1/180 19/45=1/3 + 1/15 + 1/45 19/45=1/3 + 1/18 + 1/30, 19/45=1/4 + 1/6

埃及分数问题_迭代加深搜索_C++

一.题目背景 http://codevs.cn/problem/1288/ 给出一个真分数,求用最少的1/a形式的分数表示出这个真分数,在数量相同的情况下保证最小的分数最大,且每个分数不同. 如 19/45=1/3 + 1/12 + 1/180 二.迭代加深搜索 迭代加深搜索可以看做带深度限制的DFS. 首先设置一个搜索深度,然后进行DFS,当目前深度达到限制深度后验证当前方案的合理性,更新答案. 不断调整搜索深度,直到找到最优解. 三.埃及分数具体实现 我们用dep限制搜索层数,先从2开始,每

“埃及分数”问题浅谈对迭代加深搜索的理解

迭代加深搜索(IDDFS)的思想 迭代加深搜索一般用来求解状态树"非常深",甚至深度可能趋于无穷,但是"目标状态浅"的问题.如果用普通的DFS去求解,往往效率不够高.此时我们可以对DFS进行一些改进.最直观的一种办法是增加一个搜索的最大深度限制maxd,一般是从1开始.每次搜索都要在maxd深度之内进行,如果没有找到解,就继续增大maxd,直到成功找到解,然后break. 如下图所示,如果用DFS,需要15步才能找到结点3,但是用迭代加深搜索,很快即可找到结点3.

搜索专题小结:迭代加深搜索

迭代加深搜索 迭代加深搜索(Iterative Deepening Depth-First Search, IDDFS)经常用于理论上解答树深度上没有上界的问题,这类问题通常要求出满足某些条件时的解即可.比如在"埃及分数"问题中要求将一个分数a/b分解成为若干个形如1/d的加数之和,而且加数越少越好,如果加数个数相同,那么最小的分数越大越好.下面总结一下该方法的一般流程: (1)概述:迭代加深搜索是通过限制每次dfs的最大深度进行的搜索.令maxd表示最大的搜索深度,那么dfs就只能在

UVA-11214 Guarding the Chessboard (迭代加深搜索)

题目大意:在一个国际象棋盘上放置皇后,使得目标全部被占领,求最少的皇后个数. 题目分析:迭代加深搜索,否则超时. 小技巧:用vis[0][r].vis[1][c].vis[2][r+c].vis[c-r+N]分别标志(r,c)位置相对应的行.列.主.副对角线有没有被占领(详见<入门经典(第2版)>P193),其中N表示任意一个比行数和列数都大(大于等于)的数. 代码如下: # include<iostream> # include<cstdio> # include&l

USACO/fence8 迭代加深搜索+剪枝

题目链接 迭代加深搜索思想. 枚举答案K,考虑到能否切出K个木头,那么我们当然选最小的K个来切. 1.对于原材料,我们是首选最大的还是最小的?显然,首选大的能够更容易切出,也更容易得到答案. 2.对于目标木头,我们是优先得到最大的还是最小的?显然,由于K个木头我们都要得到,那么当然先把最大的(最难得到的)先得到,这种搜索策略更优. 3.假设总原材料为all,前K个木头总和为sum,那么all-sum就是这一次切割过程中能[浪费]的最大数目.对于一个切剩下的原材料,若它比最小的目标木头还要小,则它

hdu 1560 DNA sequence(迭代加深搜索)

DNA sequence Time Limit : 15000/5000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 15   Accepted Submission(s) : 7 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description The twenty-first century