折半枚举(双向搜索)
1.
从 4 个数列中选择的话总共有 n4 种情况,所以全都判断一遍不可行。不过将它们对半分成 AB 和 CD 再考虑,就可以快速解决了。从两个数列中选择的话只有 n2 种组合,所以可以进行枚举。先从 A、B中取出 a、b 后,为了使总和为 0 则需要从 C、D中取出 c + d = - a - b。因此先将从 C、D 中取数字的 n2 种方法全部都枚举出来,将这些和排好序,这样就可以运用二分搜索。这个算法的复杂度是 O(n2 log n)。
有时候,问题的规模比较大,无法枚举所有元素的组合,但能够枚举一半元素的组合。此时,讲问题拆分两半后分别枚举,再合并它们的结果这一方法往往非常有效。
int n; int A[MAX_N], B[MAX_N], C[MAX_N], D[MAX_N];int CD[MAX_N * MAX_N]; // C和D中数字的组合方法void solve() {//枚举 C和D中取出数字的所有方法for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)CD[i * n + j] = C[i] + D[j];sort(CD, CD + n * n);long long res = 0;for (int i = 0; i < n; i++)for (int j = 0; j < n; j++) {int cd = -(A[i] + B[j]);res += upper_bound(CD, CD + n * n, cd) - lower_bound(CD, CD + n * n, cd);}printf("%lld\n", res); }
2.
这个问题显然是背包问题。不过这次价值和重量都非常大,相比之下 n 比较小。使用 DP 求解背包问题的复杂度为 O(n W),因此不能用来解决这里的问题。此时我们应该利用 n 比较小的特点来寻找其他办法。
挑选物品的方法总共有 2n 种,所有不能直接枚举,但是像前面一样拆成两半之后再枚举的话,因为每个部分只有 20 个所以是可行的。利用拆成两半后的两部分的价值和重量,我们能求处原先的问题吗?我们把前半部分中的选取方法对应的重量和价值总和记为 w1、v1.这样在后半部分寻找总重 w2 <= W - w1 时使 v2 最大的选取方法就好了。
因此,要思考从枚举得到的(w2,v2)的集合中高效寻找 max{v2 | w2 ≤ W' } 的方法。首先,显然我们可以排除所有 w2[ i ] ≤ w2[ j ] 并且 v2[ i ] ≥ v2[ j ] 的 j。这一点可以按照 w2、v2 的字典序排序后简单做到。此后剩余的元素都满足 w2[ i ] < w2[ j ] <=> v2[ i ] < v2[ j ],要计算 max{ v2 | w2 ≤ W' }的话,只需要寻求满足 w2[ i ] ≤ W' 的最大的 i 就可以了。这可以用二分搜索完成,剩余的元素个数为 M 的话,一次搜索需要 O(log M)的时间。因为 M ≤ 2(n / 2),所以这个算法的复杂度是O(2(n / 2)n)。
typedef long long ll;int n; ll w[MAX_N], v[MAX_N]; ll W;pair<ll, ll> pa[1 << (MAX_N / 2)]; // (重量,价值)void solve() {//枚举前半部分int n2 = n / 2;for (int i = 0; i < 1 << n2; i++) {ll sw = 0, sv = 0;for (int j = 0; j < n2; j++)if (i >> j & 1) {sw += w[j];sv += v[j];}ps[i] = make_pair(sw, sv);} // 去除多余元素sort(ps, ps + (1 << n2));int m = 1;for (int i = 1; i < 1 << n2; i++)if (ps[m - 1].second < ps[i].second) ps[m++] = ps[i];// 枚举后半部分并求解ll res = 0;for (int i = 0; i < 1 << (n - n2); i++) {ll sw = 0, sv = 0;for (int j = 0; j < n - n2; j++)if (i >> j & 1) {sw += w[n2 + j];sv += v[n2 + j];}if (sw <= W) {ll tv = (lower_bound(ps, ps + m, make_pair(W - sw, INF)) - 1)->second;res = max(res, sv + tv);}}printf("%lld\n", res); }
枚举方面:
#include<iostream> #include<algorithm> using namespace std; int main() {for (int i = 0; i < 1 << 4; i++)for (int j = 0; j < 4; j++)printf("%d%c", i >> j & 1, j == 3 ? '\n' : ' ');return 0;}
转载于:https://www.cnblogs.com/astonc/p/10859302.html
折半枚举(双向搜索)相关推荐
- Subset POJ - 3977(折半枚举+二分+二进制枚举)
题意: 给你一个集合N(N<=35),问集合的子集,除了空集,使得自己中所有元素和的绝对值最小,若存在多个值,那么选择子集中元素最少的那个. 题目: Given a list of N inte ...
- 2017西安交大ACM小学期 刁钻的顾客[3进制+折半枚举]
刁钻的顾客 发布时间: 2017年7月3日 10:23 时间限制: 3000ms 内存限制: 128M 描述 XJTU校园内新开一家商店,可是来了一位刁钻的顾客要购买商品A和商品B.关于商品的 ...
- poj_3977 折半枚举
题目大意 给定N(N<=35)个数字,每个数字都<= 2^15. 其中一个或多个数字加和可以得到s,求出s的绝对值的最小值,并给出当s取绝对值最小值时,需要加和的数字的个数. 题目分析 需 ...
- CodeForces888E Maximum Subsequence(折半枚举+two-pointers)
题意 给定一个包含\(n\)个数的序列\(a\),在其中任选若干个数,使得他们的和对\(m\)取模后最大.(\(n\leq 35\)) 题解 显然,\(2^n\)的暴枚是不现实的...,于是我们想到了 ...
- POJ 3373 模运算 + 折半枚举
题意 传送门 POJ 3373 题解 置换 nnn 部分数位上的数字得到 mmm,其能被 kkk 整除,且置换数位最少,有多个 mmm 满足上述条件则求最小值. 考虑到 k≤104k\leq 10^4 ...
- zstu新生赛 Problem A: Baby Coins(折半枚举+二分)
Problem A: Baby Coins Time Limit: 1 Sec Memory Limit: 128 MB Submit: 274 Solved: 29 Description Baby ...
- P4799-世界冰球锦标赛(折半枚举模板)
题目 1<=n<=40,1<=m<=1e18; 输入样例#1: 5 1000 100 1500 500 500 1000 输出样例#1: 8 01背包,m范围小的话可以使用.这 ...
- 【HDU 5936 --- Difference】折半枚举+二分
[HDU 5936 --- Difference]折半枚举+二分 Description Little Ruins is playing a number game, first he chooses ...
- 【POJ - 2785】4 Values whose Sum is 0 (二分,折半枚举)
题干: The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, com ...
最新文章
- SAP S4 OP/Cloud大乱斗
- SparkStreaming和Storm的区别
- Java程序员从笨鸟到菜鸟之(七十二)细谈Spring(四)利用注解实现spring基本配置详解
- 《机器学习实战》chapter05 Logistic回归
- array_merge与array+array的区别
- Node --- EventProxy的原理
- Java对象生命周期
- linux系统键盘记录器,可截获到 QQ 密码 键盘记录器源码
- 精通Android自定义View(十九)自定义圆形炫彩加载转圈效果
- Leetcode-1155 Number of Dice Rolls With Target Sum(掷骰子的N种方法)
- Mac 安装 valet
- group policy client服务未能登录,拒绝访问
- 日语N5名词整理:单词按发音汇总
- 计算机网络笔记 韩立刚(物理层+数据链路层+网络层+传输层已完成)
- python torch.optim.SGD
- uart硬件一些小知识
- 视频转换成gif动图如何操作?教你三步完成视频转gif
- idea修改css,js样式浏览器没更新问题
- xlsx表格怎么做汇总统计_EXCEL如何筛选表格里相同的文字并统计!
- 前端自动生成Change Log的实现
热门文章
- Blazor服务器应用程序中使用EF Core的多租户
- 具有预先训练模型的AI人脸识别
- 4400 万个微软帐户使用泄露的密码
- java web开源项目源码_超赞!推荐一个专注于Java后端源码分析的Github项目!
- 华硕z170a如何开启m2_给Z170A 加个M.2 SSD,速度有点意思
- 电脑扫描文件怎么弄_彻底清除手机垃圾文件,释放内存的方法
- 双时隙的工作原理_双作用叶片泵工作原理是怎样的?作为8年工程师都没了解这么深...
- lenovo电脑_诠释什么叫性价比?LENOVO联想ThinkPad P72/P73 ?仅售16200.00元?
- 一个小小Css3动画的案例
- established 太多_ss -s closed过多,NON_ESTABLISHED告警