题意 :

以下两个问题的物品都只能取有且只有一次

① 给你 N 个物品,所有物品的价值总和不会超过 5000, 单个物品的价格就可达 10^10 ,背包容量为 B

② 给你 N (N ≤ 40 ) 个物品,物品的单个价值和重量都达到 10^15 问你在背包容量为 W

给出 ① 和 ② 问题条件下背包所能装出来的最大价值

分析 :

① 因为单个物品的价值实在太大,如果仍然按照普通 0/1 背包的 dp 定义方法数组是开不下的

但是发现价值的总和并不大,所以从价值这里下手,定义 dp[i][j] = 从 1 ~ i 个物品背包价值为 j 时的最小重量

dp 的状态转移方程效仿普通的 0/1 背包即可,但是是取最小 dp[i][j] = min(dp[i][j], dp[i-1][j-v[i]] + w[i])

同样可以使用 0/1 背包的空间优化将 dp 数组转化为一维的来减少空间复杂度

以下是 FZU 2214 的 AC 代码

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<algorithm>
  4. #define LL long long
  5. using namespace std;
  6. ;
  7. const LL INF = 0x3f3f3f3f;
  8. LL dp[maxn], w[], B;
  9. ];
  10. int N, C;
  11.  
  12. int main(void)
  13. {
  14. int nCase;
  15. scanf("%d", &nCase);
  16. while(nCase--){
  17. scanf("%d %lld", &N, &B);
  18. C = ;
  19. ; i<=N; i++)
  20. scanf("%lld %lld", &w[i], &v[i]),
  21. C += v[i]; /// C 累加的是所有物品的价值总和
  22.  
  23. ; j<=C; j++)
  24. dp[j] = INF;/// 初始化 dp 数组应当赋予一个较大的数
  25. dp[] = ;
  26.  
  27. ; i<=N; i++)
  28. for(int j=C; j>=v[i]; j--)
  29. dp[j] = min(dp[j], dp[j-v[i]]+w[i]);
  30.  
  31. ; j--){
  32. if(dp[j] <= B){///从大到小遍历价值,第一个满足条件的 dp 数组值的下标便是答案
  33. printf("%d\n", j);
  34. break;
  35. }
  36. }
  37. }
  38. ;
  39. }

② 因为价值和重量都太过于大,数组是完全开不下了,不能记录状态,所以考虑其他方法。

如果是去暴力,那么就是暴力枚举物品的组合,然后找到一个组合使得价值最大,复杂度为 O( 2^n )

这里 max( n ) == 40 ,所以时间复杂度还是大到无法接受,考虑是否能将问题规模降下来。

考虑折半枚举法,假设现 n == 40,折半思想是先把前 2^20 个物品的组合先枚举预处理出来 2^20 个 w、v

然后如果我们能对于这枚举出来的前 2^20 个和后面 2^20 个物品的某个组合结合然后找出最优的结果

最后从这 2^20 个最优结果中再取最优就是答案,问题就是如何对于预处理出来的前 2^20 个组合与后面结合产生最优

假设现在背包容量为 C ,在前 2^20 个物品组合中取出一个,价值为 vi 重量为 wi

那么如果我们能从后 2^20 个中找出一个组合使得其在满足重量 w' ≤ C - wi 的情况下价值最大

只要对于后 2^20 个的所有组合处理出其重量和价值,然后根据重量排序且根据价值去重

这样就能用二分查找来加快查找速度!

  1. #include<bits/stdc++.h>
  2. #define LL long long
  3. using namespace std;
  4. ;
  5. const LL INF = 0x3f3f3f3f;
  6. pair<LL, LL> Pi[<<(maxn/)];
  7. LL W[maxn], V[maxn], C;
  8. int N;
  9.  
  10. int main(void)
  11. {
  12. //freopen("in.txt", "r", stdin);
  13. while(~scanf("%d %lld", &N, &C)){
  14.  
  15. ; i<N; i++)
  16. scanf("%lld %lld", &W[i], &V[i]);
  17.  
  18. ;
  19. ; i<(<<n); i++){/// 利用二进制法枚举子集,集合个数应当为 2^n
  20. LL SumW, SumV;
  21. SumW = SumV = ;
  22. ; j<n; j++){
  23. ){
  24. SumW += W[j];
  25. SumV += V[j];
  26. }
  27. }
  28. Pi[i] = make_pair(SumW, SumV);/// 将每个组合的 重量&&价值 用 pair 存起来
  29. }
  30.  
  31. sort(Pi, Pi+(<<n));/// 按照第一键值(重量)排序
  32. ;
  33. ; i<(<<n); i++)
  34. ].second < Pi[i].second)/// 这样的去重能找出在价值一样的情况下,保存最小的 w
  35. Pi[num++] = Pi[i];
  36.  
  37. ; i<num; i++){
  38. printf("%d %lld %lld", i, Pi[i].first, Pi[i].second);
  39. puts("");
  40. }
  41.  
  42. LL res = ;
  43. ; i<(<<(N-n)); i++){/// 枚举后半段的组合
  44. LL SumW, SumV;
  45. SumW = SumV = ;
  46. ; j<(N-n); j++){
  47. ){
  48. SumW += W[n+j];
  49. SumV += V[n+j];
  50. }
  51. }
  52. if(SumW <= C){
  53. ;
  54. pair<LL, LL> Temp = Pi[idx];
  55. res = max(res, SumV + Temp.second);
  56. }
  57. }
  58.  
  59. printf("%lld\n", res);
  60. }
  61. ;
  62. }

(容量超大)or(容量及价值)超大背包问题 ( 折半枚举 || 改变 dp 意义 )的更多相关文章

  1. 中南林业大学校赛 I 背包问题 ( 折半枚举 || 01背包递归写法 )

    题目链接 题意 : 中文题 分析 :  价值和重量都太过于大,所以采用折半枚举的方法,详细可以看挑战的超大背包问题 由于 n <= 30 那么可以不必直接记录状态来优化,面对每个用例 直接采用递 ...

  2. NYOJ 1091 超大01背包(折半枚举)

    这道题乍一看是普通的01背包,最最基础的,但是仔细一看数据,发现普通的根本没法做,仔细观察数组发现n比较小,利用这个特点将它划分为前半部分和后半部分这样就好了,当时在网上找题解,找不到,后来在挑战程序 ...

  3. CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

    1514: Packs Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 4[Submit][Status][Web Board] ...

  4. FZU 2214 ——Knapsack problem——————【01背包的超大背包】

    2214 Knapsack problem Accept: 6    Submit: 9Time Limit: 3000 mSec    Memory Limit : 32768 KB  Proble ...

  5. 关于ArrayList 容量问题

    ArrayList 是实现List 接口的动态数组,即它的容量大小是可变的.允许包括null 在内的所欲元素. 每个ArrayList 实例都有一个容量,该容量是指用来存储列表元素的数组的大小.默认初 ...

  6. Java中的ArrayList的初始容量和容量分配

    List接口的大小可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素.ArrayList继承于List接口,除继承过来的方法外,还提供一些方法来操作内部用来存储列表的数组的大 ...

  7. SharePoint咨询师之路:设计之前的那些事一:容量

    提示:本系列只是一个学习笔记系列,大部分内容都可以从微软官方网站找到,本人只是按照自己的学习路径来学习和呈现这些知识. 咨询师更多的时候是解决方案提供者,那么他们如何能够提供有效的SharePoint ...

  8. Android读取RAM,ROM,SD卡容量

    1)简介 一般人们在买手机的时候,在手机配置上都会出现"内存容量:512MB ROM+512MB RAM "等等类似这样的说明,可能很多人都知道RAM的意思就是运存的意思,但是对于 ...

  9. 额定能量不得超过160Wh, 等同是多少mAh电池容量?

    额定能量不得超过160Wh, 等同是多少mAh电池容量?行动电源容量标示, 正确应该是用Whr(Wh)瓦特小时来标示, 不过坊间标榜行动电源的容量通常是用xx000mAhWHr瓦特小时, 即是行动电源 ...

随机推荐

  1. 【MM系列】SAP PO增强BADI

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP PO增强BADI   前言部 ...

  2. jenkins自动化测试Email Extension邮件模板 及可用参数TEST_COUNTS ,FAILED_TESTS详细说明

    先列出模板内容: <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <t ...

  3. 【Go语言】map在goroutine通信中的使用问题

    简介 本篇文章的主要内容是解决go语言map在使用中遇到的两个问题,对于初学者是不可避免的坑 一.cannot assign to struct field 当map中存在struct类型的成员,如果 ...

  4. SecureCRT Linux系统ssh连接终端最常用快捷键

    CecureCRT连接工具常用快捷键总结: 查看 Alt + Enter 全屏 菜单 Alt + f + n 克隆会话窗口 Alt + c 在新窗口中连接,连接窗口中勾选open in a tab可以 ...

  5. [转帖]IIS7.5应用程序池集成模式和经典模式的区别介绍

    IIS7.5应用程序池集成模式和经典模式的区别介绍 之前转帖过一个 但是感觉不如这个说的细: https://www.jb51.net/article/31010.htm 关注脚本之家微信公众号(jb ...

  6. tomcat启动失败的三种方法

    Tomcat启动失败的解决办法 1. 重复映射 用eclipse开发时,用Eclipse开发,新建了的servlet会有一个url-pattern声明: 这样就不需要再在web.xml中添加映射,如果 ...

  7. 终于有人把 Docker 讲清楚了,万字详解!

    一.简介 1.了解Docker的前生LXC LXC为Linux Container的简写.可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性.相当于C++中 ...

  8. tensorflow学习笔记四----------构造线性回归模型

    首先通过构造随机数,模拟数据. import numpy as np import tensorflow as tf import matplotlib.pyplot as plt # 随机生成100 ...

  9. angularJS(三):服务(Service)、http

    一.服务 服务是一个函数或对象,可在你的 AngularJS 应用中使用. 可以创建自己的服务,或使用内建服务 $location 注意 $location 服务是作为一个参数传递到 controll ...

  10. spark(3)

    0.spark -------------------------------------------- transformation map filter repartition spark核心AP ...