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

折半枚举(双向搜索)相关推荐

  1. Subset POJ - 3977(折半枚举+二分+二进制枚举)

    题意: 给你一个集合N(N<=35),问集合的子集,除了空集,使得自己中所有元素和的绝对值最小,若存在多个值,那么选择子集中元素最少的那个. 题目: Given a list of N inte ...

  2. 2017西安交大ACM小学期 刁钻的顾客[3进制+折半枚举]

    刁钻的顾客 发布时间: 2017年7月3日 10:23   时间限制: 3000ms   内存限制: 128M 描述 XJTU校园内新开一家商店,可是来了一位刁钻的顾客要购买商品A和商品B.关于商品的 ...

  3. poj_3977 折半枚举

    题目大意 给定N(N<=35)个数字,每个数字都<= 2^15. 其中一个或多个数字加和可以得到s,求出s的绝对值的最小值,并给出当s取绝对值最小值时,需要加和的数字的个数. 题目分析 需 ...

  4. CodeForces888E Maximum Subsequence(折半枚举+two-pointers)

    题意 给定一个包含\(n\)个数的序列\(a\),在其中任选若干个数,使得他们的和对\(m\)取模后最大.(\(n\leq 35\)) 题解 显然,\(2^n\)的暴枚是不现实的...,于是我们想到了 ...

  5. POJ 3373 模运算 + 折半枚举

    题意 传送门 POJ 3373 题解 置换 nnn 部分数位上的数字得到 mmm,其能被 kkk 整除,且置换数位最少,有多个 mmm 满足上述条件则求最小值. 考虑到 k≤104k\leq 10^4 ...

  6. zstu新生赛 Problem A: Baby Coins(折半枚举+二分)

    Problem A: Baby Coins Time Limit: 1 Sec Memory Limit: 128 MB Submit: 274 Solved: 29 Description Baby ...

  7. P4799-世界冰球锦标赛(折半枚举模板)

    题目 1<=n<=40,1<=m<=1e18; 输入样例#1: 5 1000 100 1500 500 500 1000 输出样例#1: 8 01背包,m范围小的话可以使用.这 ...

  8. 【HDU 5936 --- Difference】折半枚举+二分

    [HDU 5936 --- Difference]折半枚举+二分 Description Little Ruins is playing a number game, first he chooses ...

  9. 【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 ...

最新文章

  1. SAP S4 OP/Cloud大乱斗
  2. SparkStreaming和Storm的区别
  3. Java程序员从笨鸟到菜鸟之(七十二)细谈Spring(四)利用注解实现spring基本配置详解
  4. 《机器学习实战》chapter05 Logistic回归
  5. array_merge与array+array的区别
  6. Node --- EventProxy的原理
  7. Java对象生命周期
  8. linux系统键盘记录器,可截获到 QQ 密码 键盘记录器源码
  9. 精通Android自定义View(十九)自定义圆形炫彩加载转圈效果
  10. Leetcode-1155 Number of Dice Rolls With Target Sum(掷骰子的N种方法)
  11. Mac 安装 valet
  12. group policy client服务未能登录,拒绝访问
  13. 日语N5名词整理:单词按发音汇总
  14. 计算机网络笔记 韩立刚(物理层+数据链路层+网络层+传输层已完成)
  15. python torch.optim.SGD
  16. uart硬件一些小知识
  17. 视频转换成gif动图如何操作?教你三步完成视频转gif
  18. idea修改css,js样式浏览器没更新问题
  19. xlsx表格怎么做汇总统计_EXCEL如何筛选表格里相同的文字并统计!
  20. 前端自动生成Change Log的实现

热门文章

  1. Blazor服务器应用程序中使用EF Core的多租户
  2. 具有预先训练模型的AI人脸识别
  3. 4400 万个微软帐户使用泄露的密码
  4. java web开源项目源码_超赞!推荐一个专注于Java后端源码分析的Github项目!
  5. 华硕z170a如何开启m2_给Z170A 加个M.2 SSD,速度有点意思
  6. 电脑扫描文件怎么弄_彻底清除手机垃圾文件,释放内存的方法
  7. 双时隙的工作原理_双作用叶片泵工作原理是怎样的?作为8年工程师都没了解这么深...
  8. lenovo电脑_诠释什么叫性价比?LENOVO联想ThinkPad P72/P73 ?仅售16200.00元?
  9. 一个小小Css3动画的案例
  10. established 太多_ss -s closed过多,NON_ESTABLISHED告警