迭代加深:对于可以用回溯法求解但解答树的深度没有明显上限的题目,可以考虑使用迭代加深搜索。(dfs+剪枝)
如果可以设计出乐观估价函数,则迭代加深搜索成了IDA*算法
深度递增,仿广搜,限定下界的深搜;迭代加深,剪枝。
已埃及分数为例:
题目:
http://acm.nefu.edu.cn/JudgeOnline/problemshow.php?problem_id=358
题意:某真分数,需要将其化简为最少的若干特殊真分数之和,要输出这个序列(序列按递增序)。如果有不同的方案,则分数个数相同的情况下使最大的分母最小。若还相同,则使次大的分母最大……以此类推。如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的。对于一个分数a/b,表示方法有很多种,但是哪种最好呢? 首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。
#include<iostream>
#include<stdio.h>
#include<cstring>
#define LL long long
using namespace std;
int ans[1000];
int v[1000];
int maxd;
int ok = 0;
int a, b;
int gcd(int a, int b){
return b? gcd(b, a%b):a;
}
bool better(int d)
{
for(int i = d; i >= 0; i--)
if(v[i] != ans[i])
//两种情况,1:ans[i]为-1(未更新)则更新。
//2:当前分数比目前最优分数大(优)则更新
return ans[i] == -1 || v[i] < ans[i];
return false;
}
int get_first(LL a, LL b)
{
LL c = b / a;
if( b % a ) c+=1;
return c;
}
LL max(LL a, LL b){ return a>b ? a : b; }
bool dfs(int d, int from, LL aa, LL bb)
{
if(d == maxd)
{
if( bb%aa != 0 ) return false;
v[d] = bb / aa;
if(better(d)) memcpy(ans, v, sizeof(LL) * (d+1) );
return true;
}
bool ok = false;
from = max(from, get_first(aa, bb));
for(int i = from;; i++)
{ //剪枝--*******
if(bb * (maxd + 1 - d ) <= i * aa) break;
//如果剩下的maxd-1-d个分数全部都是1/i
//加起来扔不超过aa/bb,则无解,break;称为“剪枝”
v[d] = i;
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()
{
cin>>a>>b;
//cout<<get_first(a, b)<<endl;
for(maxd = 1;; maxd++)
{
memset(ans, -1, sizeof(ans));
if(dfs (0, get_first(a, b), a, b) )
{
ok = 1; break;
}
}
for(int i = 0; ans[i] != -1; i++)
{
printf(" 1/%d", ans[i]);
}
}