迭代加深
迭代加深是用于优化搜索的,因为dfs的过程中是选择搜索的一个分支,不断地深入,直到我们达到递归的边界时才会返回。这样的话,如果搜索树的分支比较多,但答案在比较浅的分支节点时,一旦我们选择了错误的搜索分支,我们就会在错误的分支上搜索到很深的深度从而浪费搜索的时间。而迭代加深就是为了解决这一问题,迭代加深的思想是,限制我们搜索的最大深度,当我们在当前最大深度搜索不到答案时,再增大深度继续搜索,就这样一圈一圈向外扩展,有点类似bfs,但与bfs不同的时,不会存储一层的节点,空间复杂度仍然是O(h),(h是搜索树的高度)。
加成序列
#include <iostream>
#include <cstring>
using namespace std;
const int N = 110;
int path[N], n;
bool dfs(int u, int depth)
{
if(u > depth) return false;
if(path[u - 1] == n) return true;
bool st[N] = {0};
int s = 0;
for(int i = u - 1; i >= 0; -- i)
for(int j = i; j >= 0; -- j)
{
s = path[i] + path[j];
if(s > n || s < path[u - 1] || st[s]) continue;
path[u] = s;
//标记一下排除等效冗余,因为可能两个数的相加是一样的,这样就是虽然过程不同,但得到的序列是一样的
//所以需要剪枝排除不必要的
st[s] = 1;
if(dfs(u + 1, depth)) return true;
}
return false;
}
int main()
{
while(cin >> n, n)
{
int depth = 1;
path[0] = 1;
while(!dfs(1, depth)) depth ++;
for(int i = 0; i < depth; ++ i) cout << path[i] << ' ';
cout << endl;
}
return 0;
}
双向搜索
送礼物
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 46;
int w[N];
int weight[1 << 26], cnt = 1;
int n, m, k, ans;
//预处理前面k个物品并打表
void dfs1(int u, int s)
{
//枚举到第k个物品,也就是终点
if(u == k)
{
//将当前组合加入weight中
weight[cnt ++] = s;
return ;
}
//枚举不选择当前物品的情况
dfs1(u + 1, s);
//枚举选择当前物品的情况
if((LL) s + w[u] <= m) dfs1(u + 1, s + w[u]);
}
//后半部分搜索
void dfs2(int u, int s)
{
//枚举到最后一个物品,搜索到终点
if(u == n)
{
//在weight中查找最大的位置使weight <= m - s
int l = 0, r = cnt - 1;
while(l < r)
{
int mid = (l + r + 1) >> 1;
if(weight[mid] <= m - s) l = mid;
else r = mid - 1;
}
ans = max(ans, s + weight[l]);
return;
}
dfs2(u + 1, s);
if((LL)s + w[u] <= m) dfs2(u + 1, s + w[u]);
}
int main()
{
cin >> m >> n;
for(int i = 0; i < n; ++ i) cin >> w[i];
//优化一下搜索顺序
sort(w, w + n);
reverse(w, w + n);
k = n / 2;
dfs1(0, 0);
sort(weight, weight + cnt);
cnt = unique(weight, weight + cnt) - weight;
dfs2(k, 0);
cout << ans << endl;
return 0;
}