对于可以用回溯法求解但解答树的深度没有明显上限的题目,可以考虑使用迭代加深搜索。
经典问题:埃及分数问题
给出一个分数,比如19/45,把它写成若干个形如1/Ri的分数的和的形式,比如19/45=1/5+1/6+1/18,要求分母不能重复使用并且使用的分数的个数最少。(如果有多组个数相同的解,最后的分数的分母越小越好,这对于题目来说是次要的。)
1、分母从小到大搜索
为了避免重复搜索
2、使用迭代加深搜索
求“步骤数最少”这类问题,基本上有两种似乎:广搜、迭代加深搜索。对于这道题来说,如果广搜将永远得不到结果,分母可以无限大!但是迭代加深搜索就比较好,虽然做了许多重复工作,但状态空间至少被限制住了。如果当前正在枚举的分母,使得接下来的选择即使每次都选择最大,达到最大深度的时候也不可能达到目标分数,那么当前正在枚举的分母及比它还大的分母,都不需要枚举了。这样可以给分母确定一个上界。另外,已经得到的结果加上当前枚举的分母对应的分数,要小于等于目标分数,这样给分母确定了一个下界(可以在O(1)的复杂度内确定这个下界)。
大神的代码~
int a, b;
int tree[1000];
bool dfs(int deep, int cb, int sa, int sb ) {
tree[deep] = cb;
int _a = sb + cb * sa;
int _b = cb * sb;
// 同一层向右平移, 找一个更小的分数。
if ((_a * b) > (a * _b)) return dfs(deep, cb + 1, sa, sb);
// 递归边界:是否达到最大层数限制。
if ( deep == 0 ) {
if ((_a * b) == (a * _b)) return true;
else return false;
}
else return dfs( deep-1, 2, _a, _b); // 移向下一层
return false;
}
void iterativeDeepening() {
int deep = 0;
for (; deep <= 1000; deep++ ) { // 迭代加深
if (dfs(deep,2,0,1)) break;
}
for (int i = 0; i <=deep; i++) {
printf("1/%d ", tree[i]);
}
}
int main () {
while(scanf("%d%d",&a,&b) == 2){
iterativeDeepening();
}
system("PAUSE");
return 0;
}