剪枝
剪枝
剪枝是搜索中很重要的一个环节, 尽早排除搜索树中不必要的分支。
优化搜索顺序
优先搜索分支数量较小的节点
排除等效冗余
比如从n个物品选m个物品,选1,2和选2,1是一样的,这样我们只需要遍历其中一个即可,如果不考虑顺序的话尽量按组合的顺序搜索
可行性剪枝
当我们搜索状态在进行中发现不合法了就可以提前退出
最优性剪枝
在最优性问题中,我们在搜索时发现,当前正在搜索的答案,已经比我们已经搜索到的答案差的话,就可以提前退出
记忆化
多用在实现dp中,将已经遍历过的状态进行记录,不用重复访问同一状态
例1
这道题目用到了优化搜索顺序,可行性剪枝和最优化剪枝,详细见代码里面的注释
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 20;
int a[N], cap[N];
int n, m, ans = N;
void dfs(int u, int cnt)
{
//最优化剪枝:当前答案已经大于我们已经搜到的最优解
if(cnt >= ans) return;
//找到了新的一组解,并且当前解是比已经搜到的最优解更优,更新最优解
if(u == n)
{
ans = cnt;
return;
}
for(int i = 0; i < cnt; ++ i)
//可行性剪枝,当前答案已经非法
if(cap[i] + a[u] <= m)
{
cap[i] += a[u];
dfs(u + 1, cnt);
cap[i] -= a[u];
}
cap[cnt] = a[u];
dfs(u + 1, cnt + 1);
cap[cnt] = 0;
}
int main()
{
cin >> n >> m;
for(int i = 0; i < n; ++ i) cin >> a[i];
//优化搜索顺序,放重量较大的,搜索树的分支会更小
sort(a, a + n);
reverse(a, a + n);
dfs(0, 0);
cout << ans << endl;
return 0;
}