【笔记】搜索姿势

感觉给博客配图的速度可能要跟不上了(

折半搜索

原来的链接
一般的形式:

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 题解

posted @ 2021-08-03 11:24  zrkc  阅读(40)  评论(0)    收藏  举报