dp-多重背包
(推荐 : http://blog.csdn.net/insistgogo/article/details/11176693 )
学会了前两个背包 , 学这个背包还是很轻松的 。
多重背包 , 顾名思义 , 就是前两种背包结合到一起 , 首先还是用一个例子说明 。
1、问题描述
已知:有一个容量为V的背包和N件物品,第i件物品最多有Num[i]件,每件物品的重量是weight[i],收益是cost[i]。
问题:在不超过背包容量的情况下,最多能获得多少价值或收益

多重背包 区别于二重背包的地方就在于 所给出的物品数是有限的 。
用二维数组写出代码 :
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std ;
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a int dp[100][1000] ;
int weight[10] ;
int value[10] ;
int num[10] ; int main ( ) {
int n , v ;
cin >> n >> v ; for ( int i = 1 ; i <= n ; i++ ) {
cin >> weight[i] >> value[i] >> num[i] ;
} for ( int i = 1 ; i <= n ; i++ ) {
for ( int j = weight[i] ; j <= v ; j++ ) {
int f = Min ( num[i] , j / weight[i] ) ;
for (int k = 1 ; k <= f ; k*=2 ) { // 三层 for , 最内层的for 用来进行在进行在 每种物品的每种体积下,一直放入同一种物品
// 此处有一个小的优化 , 就是我每种物品的数量通过 1、2、4、8、16……2^k 来控制
dp[i][j] = Max ( dp[i-1][j] , dp[i-1][j-k*weight[i]]+k*value[i] ) ;
// cout << dp[i][j] << '\t' ;
} }
// cout << '\n' ;
} cout << dp[n][v] << endl ;
return 0 ;
}
上述的优化方法就采用了二进制的思想
对每件物品拆分 , 拆分的数量可以是 1件 、 2件 、 4件 ……2^k 件,并且要保证 2^k <= num[ i ] ,但是这里的最后一件是 num[ i ] - 前面所有物品的和 , 那么对 num[ i ] 来说 , 就一定会有前面的 数相加等于 num[ i ] ,其实这样对物品拆分 , 在取得话 , 就可以看成每件新拆分出的物品只有一件 , 进而不就转换成 01背包了吗 ,一定要注意领悟这个拆分的思想 , 是讲背包的物品总数分解开 。
优化 :
说到拆分 , 有种情况是不用拆分的 , 就是当 weight[ i ] * num[ i ] >= v ,因为这种情况就可以理解成物品的数量充足 ,那么不就转化成 完全背包的情况吗 ? 直接就会被优化到 O(v*n) 。
对于不满足完全背包情况的物品进行拆分 , 此时物品的个数就没有对所有物品进行拆分的个数多 , 那么循环的次数就会降下来 , 复杂度也就降低了 。
代码示例 :
#include <iostream>
using namespace std; const int N = 3;//物品个数
const int V = 8;//背包容量
int Weight[N + 1] = {0,1,2,2};
int Value[N + 1] = {0,6,10,20};
int Num[N + 1] = {0,10,5,2}; int f[V + 1] = {0};
/*
f[v]:表示把前i件物品放入容量为v的背包中获得的最大收益。
f[v] = max(f[v],f[v - Weight[i]] + Value[i]);
v的为逆序
*/
void ZeroOnePack(int nWeight,int nValue)
{
for (int v = V;v >= nWeight;v--)
{
f[v] = max(f[v],f[v - nWeight] + nValue);
}
} /*
f[v]:表示把前i件物品放入容量为v的背包中获得的最大收益。
f[v] = max(f[v],f[v - Weight[i]] + Value[i]);
v的为增序
*/
void CompletePack(int nWeight,int nValue)
{
for (int v = nWeight;v <= V;v++)
{
f[v] = max(f[v],f[v - nWeight] + nValue);
}
} int MultiKnapsack()
{
int k = 1;
int nCount = 0;
for (int i = 1;i <= N;i++)
{
if (Weight[i] * Num[i] >= V)
{
//完全背包:该类物品原则上是无限供应,
//此时满足条件Weight[i] * Num[i] >= V时,
//表示无限量供应,直到背包放不下为止.
CompletePack(Weight[i],Value[i]);
}
else
{
k = 1;
nCount = Num[i];
while(k <= nCount)
{
ZeroOnePack(k * Weight[i],k * Value[i]);
nCount -= k;
k *= 2;
}
ZeroOnePack(nCount * Weight[i],nCount * Value[i]);
}
}
return f[V];
} int main()
{
cout<<MultiKnapsack()<<endl;
system("pause");
return 1;
}
dp-多重背包的更多相关文章
- HDOJ(HDU).2844 Coins (DP 多重背包+二进制优化)
HDOJ(HDU).2844 Coins (DP 多重背包+二进制优化) 题意分析 先把每种硬币按照二进制拆分好,然后做01背包即可.需要注意的是本题只需要求解可以凑出几种金钱的价格,而不需要输出种数 ...
- HDOJ(HDU).1059 Dividing(DP 多重背包+二进制优化)
HDOJ(HDU).1059 Dividing(DP 多重背包+二进制优化) 题意分析 给出一系列的石头的数量,然后问石头能否被平分成为价值相等的2份.首先可以确定的是如果石头的价值总和为奇数的话,那 ...
- HDOJ(HDU).2191. 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (DP 多重背包+二进制优化)
HDOJ(HDU).2191. 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (DP 多重背包+二进制优化) 题意分析 首先C表示测试数据的组数,然后给出经费的金额和大米的种类.接着是每袋大米的 ...
- poj1014 dp 多重背包
//Accepted 624 KB 16 ms //dp 背包 多重背包 #include <cstdio> #include <cstring> #include <i ...
- Buns(dp+多重背包)
C. Buns time limit per test 2 seconds memory limit per test 256 megabytes input standard input outpu ...
- CodeForces922E DP//多重背包的二进制优化
https://cn.vjudge.net/problem/1365218/origin 题意 一条直线上有n棵树 每棵树上有ci只鸟 在一棵树底下召唤一只鸟的魔法代价是costi 每召唤一只鸟,魔法 ...
- BZOJ.3425.[POI2013]Polarization(DP 多重背包 二进制优化)
BZOJ 洛谷 最小可到达点对数自然是把一条路径上的边不断反向,也就是黑白染色后都由黑点指向白点.这样答案就是\(n-1\). 最大可到达点对数,容易想到找一个点\(a\),然后将其子树分为两部分\( ...
- hdu1059 dp(多重背包二进制优化)
hdu1059 题意,现在有价值为1.2.3.4.5.6的石头若干块,块数已知,问能否将这些石头分成两堆,且两堆价值相等. 很显然,愚蠢的我一开始并想不到什么多重背包二进制优化```因为我连听都没有听 ...
- ACM学习历程—HDU 1059 Dividing(dp && 多重背包)
Description Marsha and Bill own a collection of marbles. They want to split the collection among the ...
- POJ 1742 Coins ( 经典多重部分和问题 && DP || 多重背包 )
题意 : 有 n 种面额的硬币,给出各种面额硬币的数量和和面额数,求最多能搭配出几种不超过 m 的金额? 分析 : 这题可用多重背包来解,但这里不讨论这种做法. 如果之前有接触过背包DP的可以自然想到 ...
随机推荐
- 机器学习——EM
整理自: https://blog.csdn.net/woaidapaopao/article/details/77806273?locationnum=9&fps=1 EM算法是用于含有隐变 ...
- linux 禁止单个中断
有时(但是很少!)一个驱动需要禁止一个特定中断线的中断递交. 内核提供了 3 个函数为 此目的, 所有都声明在 <asm/irq.h>. 这些函数是内核 API 的一部分, 因此我们描述它 ...
- dijkstra堆优化(multiset实现->大大减小代码量)
例题: Time Limit: 1 second Memory Limit: 128 MB [问题描述] 在电视时代,没有多少人观看戏剧表演.Malidinesia古董喜剧演员意识到这一事实,他们想宣 ...
- 乐视X3-40S智能电视的简化系统刷机
步骤 USB2.0-U盘一个. 先把letv原厂包里的.bin文件放入U盘刷入电视 (U盘插在电视上方的USB2.0插口处,在电视待机状态下用遥控器依次按下[3].[6].[9].[5].[开机]键, ...
- 搭建zookeeper出现错误:starting zookeeper... already running process 2853
今天搭建zookeeper时碰到了starting zookeeper already running process 2853这样一个错误. 上网上查了几个相似的问题都是要删除zookeeper_s ...
- 2019-8-31-C#-如何写-DEBUG-输出
title author date CreateTime categories C# 如何写 DEBUG 输出 lindexi 2019-08-31 16:55:58 +0800 2018-2-13 ...
- Spring Boot 嵌入式Web容器
目录 前言 1.起源 2.容器启动流程解析 2.1.获取应用类型 2.2.容器启动流程 3.加载 Web 容器工厂 4.总结 前言 最近在学习Spring Boot相关的课程,过程中以 ...
- Hyperledger Fabric动态配置Raft节点
Hyperledger Fabric动态配置Raft节点 最近看官方文档发现新的共识算法etcdRaft允许动态添加或删除排序节点,所以也花了一天时间操作了以下,写篇文章把整个过程记录一下. 初始网络 ...
- javaweb项目添加log4j日志
谈到我们在Java程序中经常用的日志,Log4j应该是耳熟能详了.这里先提下slf4j,英文全名是Simple Logging Facade for Java,直面意思是:Java的简单日志门面.sl ...
- java引用类型的浅拷贝与深拷贝理解
1.浅拷贝 只会复制地址值,也就是同一个对象两个引用,只是复制了一个引用而已. 2.深拷贝 重新在堆里创建一个新对象给新引用,连同地址值也不一样. 首先要知道Object的clone()方法, pub ...