深度优先搜索每次选定一个分支,不断深入,直至到达递归边界才回溯。这种策略大有一定的缺点。试想以下情况:搜索树每个节点的分支数目非常多,并且问题的答案在某个较浅的节点上。如果深搜在一开始选错了分支,就很可能在不包含答案的深层子树上浪费许多时间。
此时,我们可以从小到大限制搜索的深度,如果在当前深度限制下搜不到答案,就把深度限制增加,重新进行一次搜索,这就是 迭代加深 思想。所谓“迭代”,就是以上一次的结果为基础,重复执行以逼近答案的意思。
虽然该过程在深度限制为d时,会重复搜索第1~d - 1层的节点,但是当搜索树节点分支数目较多时,随着层数的深入,每层节点数会呈指数级增长,这点重复搜索与深层子树的规模相比,实在是小巫见大巫了。
总而言之,当搜索树规模随着层次的深入增长很快,并且我们能够确保答案在一个较浅的节点时,就可以采用迭代加深的深度优先搜索算法来解决问题中。读者可以进行大致的估算,有些题目描述甚至会包含“如果10步以内搜不到结果就算无解”的字样。
题意 :
思路 :
#include
using namespace std;
const int N = 10, M = 210;
int n;
int path[N];
bool dfs(int u, int k) {
if (u == k) return path[u - 1] == n;
bool st[M] = {0};
for (int i = u - 1; i >= 0; -- i) {
for (int j = i; j >= 0; -- j) {
int s = path[i] + path[j];
if (st[s] || s > n || s <= path[u - 1]) continue;
st[s] = true;
path[u] = s;
if (dfs(u + 1, k)) return true;
}
}
return false;
}
int main() {
path[0] = 1;
while (cin >> n, n) {
int k = 1;
while (!dfs(1, k)) ++ k;
for (int i = 0; i < k; ++ i) cout << path[i] << ' ';
cout << endl;
}
}
除了迭代加深之外,双向搜索也可以避免在深层子树上浪费时间。在一些题目中,问题不但具有“初态”,还具有明确的“终态”,并且从初态开始搜索与从终态开始逆向搜索产生的搜索树都能覆盖整个状态空间,在这种情况下,就可以采用 双向搜索——从初态和终态出发各搜索一半状态,产生两颗深度减半的搜索树,在中间交汇,组合成最终的答案。
如下图所示,左侧是直接进行一次搜索产生的搜索树,右侧是双向搜索的两颗搜索树,避免了层数过深时分支数量的大规模增长。

题意 :
思路 :
#include
#include
using namespace std;
typedef long long ll;
const int N = 47, M = 1 << 24;
int n, m;
int g[N];
int weights[M], cnt;
int k, mx;
void dfs(int u, int s) {
if (u == k) {
weights[cnt ++ ] = s;
return ;
}
if ((ll)s + g[u] <= m) dfs(u + 1, s + g[u]);
dfs(u + 1, s);
}
void dfs2(int u, int s) {
if (u == n) {
int l = 0, r = cnt - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if ((ll)weights[mid] + s <= m) l = mid;
else r = mid - 1;
}
if ((ll)weights[l] + s <= m) mx = max(mx, weights[l] + s);
return ;
}
if ((ll)s + g[u] <= m) dfs2(u + 1, s + g[u]);
dfs2(u + 1, s);
}
int main() {
cin >> m >> n;
for (int i = 0; i < n; ++ i) cin >> g[i];
sort(g, g + n);
reverse(g, g + n);
k = n / 2;
dfs(0, 0);
sort(weights, weights + cnt);
int t = 1;
for (int i = 1; i < cnt; ++ i) {
if (weights[i] != weights[i - 1]) {
weights[t ++ ] = weights[i];
}
}
cnt = t;
dfs2(k, 0);
cout << mx;
}