【笔记】搜索姿势
感觉给博客配图的速度可能要跟不上了(
折半搜索
原来的链接
一般的形式:
void dfs(int l, int r, ll sum, int tp)
{
if (l > r) Q[tp][++tot[tp]] = sum;
else {
dfs(l+1, r, sum-A[l], tp);
dfs(l+1, r, sum+A[l], tp);
dfs(l+1, r, sum, tp);
}
}
dfs(1, N>>1, 0, 0), dfs((N>>1)+1, N, 0, 1);
这里强调一下天平问题(或者说这种刻画方式)
求满足以下条件的子集个数,使得该子集可以划分成加和相等的两部分
先考虑一般做法,对全集中的每个元素,都取 1, 0, -1 之一,搜索出的答案对应即为所有天平的放置方式(注意到此时求得的等于 0 的方案数是实际方案数的 2 倍加 1 ,因为对称性以及空集),这样的话是 \(O(3^N)\)
考虑折半搜索,左半边与右半边做匹配,这样的话是 \(O(3^{\frac{N}{2}}+合并)\)
例题 P3067 [USACO12OPEN]Balanced Cow Subsets G
选与不选,序关系下的剪枝
写法上的问题
对于一个存方案的数列,我们搜索其子集,如何让这个子集在搜索顺序上满足下标的单调不减?
记录当前能够取到的范围,一般是记录 k ,则范围 [k, N]
如果方案数组本身就有某种序关系的话,我们可以利用这种关系剪枝或证明结论之类的,见下面的题
void dfs(int k, ...)
{
if (边界) { ... return; }
for (int i=k; i<=tot; i++) { // tot 所有方案数
// 对于下标为 i 的方案
dfs(i+1, ...(取i)); // 如果单个方案能重复取,则仍为 i
dfs(i+1, ...(不取i));
...
}
}
例题:
luoguP1120 多次取的情况,k 下传为 1 ,重来一遍就行了
POJ1167 The Buses 题解

浙公网安备 33010602011771号