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

谢谢阿苏~http://blog.csdn.net/urecvbnkuhbh_54245df/article/details/5856756

【迭代加深搜索(ID,iterative deepening)】:从小到大枚举上限maxd,每次执行只考虑深度不超过maxd的结点。

  ------对于可以用回溯法求解但解答树的深度没有明显上限的题目,可以考虑ID算法;

  ------优点:它主要是在递归搜索函数的开头判断当前搜索的深度是否大于预定义的最大搜索深度,如果大于,就退出这一层的搜索,如果不大于,就继续进行搜索。这样最终获得的解必然是最优解。它避免了广度优先搜索占用搜索空间太大的缺点,也减少了深度优先搜索的盲目性。

【A*算法(启发式搜索)】:A*(A-Star)算法是一种静态路网中求解最短路最有效的直接搜索方法。估价值与实际值越接近,估价函数取得就越好。

  A*算法的估价函数可表示为:f‘(n) = g‘(n) + h‘(n)

  这里,f‘(n)是估价函数,g‘(n)是起点到节点n的最短路径值,h‘(n) 是n到目标的最短路经的启发值。由于这个f‘(n)其实是无法预先知道的,所以我们用前面的估价函数f(n)做近似。g(n)代替g‘(n),但 g(n)>=g‘(n)才可(大多数情况下都是满足的,可以不用考虑),h(n)代替h‘(n),但h(n)<=h‘(n)才可(这一点特别的重要)。可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。我们说应用这种估价函数的最好优先算法就是A*算法。举一个例子,其实广度优先算法就是A*算法的特例。其中g(n)是节点所在的层数,h(n)=0,这种h(n)肯定小于h‘(n),所以由前述可知广度优先算法是一种可采纳的。实际也是。当然它是一种最臭的A*算法。

【IDA*算法】:综合了A*算法的人工智能性和回溯法对空间的消耗较少的优点,在一些规模很大的搜索问题中会起意想不到的效果。它的具体名称是 Iterative Deepening A*, 1985年由Korf提出。该算法的最初目的是为了利用深度搜索的优势解决广度A*的空间问题,其代价是会产生重复搜索。归纳一下,IDA*的基本思路是:首先将初始状态结点的H值设为阈值maxH,然后进行深度优先搜索,搜索过程中忽略所有H值大于maxH的结点;如果没有找到解,则加大阈值maxH,再重复上述搜索,直到找到一个解。在保证H值的计算满足A*算法的要求下,可以证明找到的这个解一定是最优解。在程序实现上,IDA* 要比 A* 方便,因为不需要保存结点,不需要判重复,也不需要根据 H值对结点排序,占用空间小。
而这里在IDA*算法中也使用合适的估价函数,来评估与目标状态的距离。

在一般的问题中是这样使用IDA*算法的,当前局面的估价函数值+当前的搜索深度 > 预定义的最大搜索深度时,就进行剪枝。

这个估计函数的选取没有统一的标准,找到合适的该函数并不容易,但是可以大致按照这个原则:在一定范围内加大各个状态启发函数值的差别。

e.g.经典埃及分数问题:

要求给你个真分数,你需要将其化简为最少的若干特殊真分数之和,你要输出这个序列(序列按递增序)。
如果有不同的方案,则分数个数相同的情况下使最大的分母最小。若还相同,则使次大的分母最大……以此类推。
如: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 + 1/180
19/45=1/5 + 1/6 + 1/18
最好的是最后一种,因为18 比180, 45, 30,都小。

输入整数a, b,编程计算最佳表达式。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<set>
 6 using namespace std;
 7 typedef long long LL;
 8 const int maxn = 100010;
 9 LL ans[maxn], v[maxn], maxd;//枚举深度上限
10 LL get_first(LL a, LL b)
11 {
12     return b/a+1;
13 }
14 LL gcd(LL a, LL b)
15 {
16     return b == 0 ? a : gcd(b, a%b);
17 }
18 bool better(LL d)
19 {
20     for(LL i = d; i >= 0; i--)
21     {
22         if(v[i] != ans[i])
23         {
24             return (ans[i] == -1 || v[i] < ans[i]);
25         }
26     }
27     return false;
28 }
29 bool dfs(LL d, LL c, LL a, LL b)
30 {
31     //cout << a << " " << b << endl;
32     if(d == maxd)
33     {
34         if(b%a) return false; //若到最大深度时最后一个分数不能化为埃及分数。即分子为1的情况
35         v[d] = b/a; //深度为d时的最优埃及分数是 1/(b/a);
36         if(better(d))
37         {
38             memcpy(ans, v, sizeof(LL)*(d+1));
39         }
40         return true;
41     }
42     bool ok = false;
43     c = max(c, get_first(a, b));
44     for(LL i = c; ; i++)
45     {
46         if((maxd-d+1) * b <= a * i) break;
47         v[d] = i;
48         LL a2 = a*i-b, b2 = b*i;
49         LL g = gcd(a2, b2); //约分
50         if(dfs(d+1, i+1, a2/g, b2/g)) ok = true;
51     }
52     return ok;
53 }
54 int main()
55 {
56     int T;
57     scanf("%d", &T);
58     for(int kase = 1; kase <= T; kase++)
59     {
60         LL a, b;
61         scanf("%lld%lld", &a, &b);
62
63         /*main code*/
64         for(maxd = 1; ; maxd++) //枚举深度上限
65         {
66             memset(ans, -1, sizeof(ans));
67             memset(v, -1, sizeof(v));
68             LL c = get_first(a, b);
69             if(dfs(0, c, a, b))
70             {
71                 break;
72             }
73         }
74         /*-------------------------------------*/
75         printf("Case %d: %lld/%lld=", kase, a, b);
76         for(int i = 0; i <= maxd; i++)
77         {
78             if(i) printf("+");
79             printf("1/%lld", ans[i]);
80         }
81         printf("\n");
82
83     }
84     return 0;
85 }

时间: 2024-10-06 10:42:40

【迭代加深搜索】埃及分数问题的相关文章

迭代加深,埃及分数

问题描述: 给出一个分数,由分子a 和分母b 构成,现在要你分解成一系列互不相同的单位分数(形如:1/a,即分子为1),要求:分解成的单位分数数量越少越好,如果数量一样,最小的那个单位分数越大越好. 如: 19/45 = 1/3 + 1/12 + 1/180; 19/45 = 1/5 + 1/6 + 1/18; 由于,1/18比1/180更大,所以第二种情况更优. 59/211=1/4 + 1/36 + 1/633 + 1/3798 59/211=1/6 + 1/9 + 1/633 + 1/37

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

hdu 1560 迭代加深搜索

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1560 只能说bin神太给力了.. 又学到不少新知识.. 迭代加深搜索,貌似 又叫IDA*, 就是给搜索深度一个限制,搜索到一个满足条件就结束. 注意剪枝~ 代码: #include <iostream> #include <cstdio> #include <cstring> using namespace std; char g[10][10]; int size[10];