引子
迭代加深搜索的实质就是限制搜索层数的暴搜。在了解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;
}