浅谈迭代加深(iddfs)

引子

迭代加深搜索的实质就是限制搜索层数的暴搜。在了解DFS的基础上,iddfs其实是很好理解的。只是需要多一个枚举层数的过程再在搜索里面判断一下层数。

gm的版子(伪代码)

IDDFS ( int current_depth  ,  int max_depth )   //当前深度,最大深度
{
       if ( current_depth > max_depth ) return ;
       if ( 找到答案 ) { 输出答案 ; (exit(0) ;  ||  return ;) }
       for each ( 当前节点的儿子节点 )
       {
 	IDDFS ( current_depth+1  ,  max_depth ) ;
       }   
}
//在main函数中,调用IDDFS
for ( int  i = min_depth ; ; i++ )
{
       IDDFS ( 0 , i ) ;
}

例题

埃及分数

题目描述

在古埃及,人们使用单位分数的和(形如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 + 1/180
19/45=1/5 + 1/6 + 1/18.
最好的是最后一种,因为1/18比1/180,1/45,1/30,1/180都大。
给出a,b(0<a<b<1000),编程计算最好的表达方式

思路

这道题用暴搜是基本无法实现的。首先我们并不知道需要多少个分数,也不知道最大的分母有多大。其递归层数和深度都是无限的。

因为我们只需要求到最优解,所以通过枚举深度(从小到大)我们是可以对递归层数进行限制的。那么如何枚举每一个分母的大小呢?
假设我们需要枚举的分数为\(\frac{a}{b}\)
当前分数的分母一定大于 \(\frac{b}{a}\)的所以下界为\(\frac{b}{a}\),那我们如何求上界呢?
因为我们限制了递归的层数,假设递归的最深层数为\(x\), 当前层数为\(y\), 那么 \(frac{x - y}{k}\) 一定\(>\) \(\frac{a}{b}\)的。
进行移项后,我们可以得到 \(k <= (y - x + 1) \times \frac{b}{a}\)

代码

#include <cstdio>
#include <cstring>
#include <algorithm> 
#include <cstdlib>//好东西 
#define int long long
using namespace std;
const int maxn = 1005;

int gcd(int x, int y){
	if(y == 0)return x;
	return gcd(y, (x % y));
}
int a, b;
int maxt;
int ans[maxn * maxn];
int ans2[maxn * maxn];
bool flag;
int t;
int sum;

//int Fibonacci(int a, int b, int num){
//	if(b % a == 0)return num;
//	int Gcd = gcd(a, b);
//	a /= Gcd;
//	b /= Gcd;
//	ans2[num] = (b / a + 1);
//	a = (b / a) * a - b;
//	b *= (b / a);
//	return Fibonacci(a, b, num + 1);
//}

void dfs(int a, int b, int num, int maxt){
	if(num > maxt)return;
	int Gcd = gcd(a, b);
	a /= Gcd;
	b /= Gcd;
//	if(b % a == 0){
//		ans[num] = b / a;
//		if(ans[num] > ans[num - 1]){
//			if(num == sum && num <= maxt && ans[num] < ans[sum]){
//				for(int i = 1; i <= num; i ++){
//					ans2[i] = ans[i];
//				}
//			}
//			if(num <= maxt && (num < sum || !flag)){
//				for(int i = 1; i <= num; i ++){
//					ans2[i] = ans[i];
//				}
//			}
//			flag = 1;
//			sum = num;
//		}
//		return;
//	}
	if(b % a == 0 && (b / a) > ans[num - 1]){
		ans[num] = b;
		if(!flag || ans[num] < ans2[num]){
			for(int i = 1; i <= num; i ++){
				ans2[i] = ans[i];
			}
			flag = 1;
			sum = num; 
		}
		return;
	}
	int s = b / a + 1;
	if(s <= ans[num - 1])s = ans[num - 1] + 1;
	int t = (maxt - num + 1) * (b / a);
	if(flag && t >= ans2[sum])t = ans2[sum] - 1; 
	for(int i = s; i <= t; i ++){
		ans[num] = i;
		dfs(a * i - b, b * i, num + 1, maxt);  
	}
}
signed main() {
	scanf("%lld %lld", &a, &b);
//	int t = Fibonacci(a, b, 1);
	for(int i = 1; ; i ++){
		flag = 0;
		dfs(a, b, 1, i);
		if(flag){
			for(int j = 1; j <= sum; j ++){
				printf("%lld ", ans2[j]);
			}
			return 0;
		}
	}
	return 0;
}
上一篇:在Linux应用程序中打印函数调用栈


下一篇:二叉树——104. 二叉树的最大深度