浅谈多重背包
来源:互联网 发布:炼数成金算法导论视频 编辑:程序博客网 时间:2024/06/05 09:08
多重背包,基础背包问题之三。
具体问题是这样的。一个容量为V的背包,还有一些物品(每个物品有具体的数量c),这些物品的体积w和价值p各不相同。求出能在不超过V的情况下尽可能的使价值最大。
对于多重背包问题,可以根据每个物品的数量分解成两种情况:
1.当c >= V / w时,相当于物品可以无限使用,即转化为完全背包求解。
2.当c < V / w时, 可转化为放物品的数量为1、2、3……c个,即转化为01背包求解。
但是上面这种方法的时间复杂度为O(V连加M),其中M为数量。这个复杂度是很大的,可以用二进制拆分优化一下。
二进制拆分:任何数num都可以拆分为2^k的加和的形式,即:
num = 2^k1 + 2^k2 + …… + 2^kn (其中kn可以取任意非负整数)
这样上面的第二种情况就可以利用这种方法进行优化,使遍历从1、2、3……c优化到1、2、4……2^k,时间复杂度为O(V连加logM)。这种优化程度就可以应对大部分题目了。(当然,对于一些卡时间的题目也不行,需要优先队列优化)。
还有一点,看懂这一点就能看懂二进制优化的核心了。
对于使用二进制拆分成的一组数字:1、2、4、8……,这些数字之间缺少3、5、6、7这样的数字,在遍历的时候没有遍历他们,因为这些数字可以由前面遍历过的数字拼凑合成。比如,3可以由1和2合成,5可以由1和4合成,以此类推。还有,比如,如果最终结果包含5,那在遍历的时候就可能记录1和4,也就是说最终结果是1和4这两件被拆分的物品,最后合到一起就是5了。
就是这种方法,使不用被遍历的数字也能出现在过程中,这就是二进制优化的精髓!
以下为程序流程:
void MultiplePack(int w, int p, int m)
{
if (w * m >= p)
{
CompletePack(w, p);
return;
}
int k = 1;
while (k < m)
{
ZeroOnePack(k * w, k * p);
m -= k;
k *= 2;
}
ZeroOnePack(m * w, m * p);
具体问题是这样的。一个容量为V的背包,还有一些物品(每个物品有具体的数量c),这些物品的体积w和价值p各不相同。求出能在不超过V的情况下尽可能的使价值最大。
对于多重背包问题,可以根据每个物品的数量分解成两种情况:
1.当c >= V / w时,相当于物品可以无限使用,即转化为完全背包求解。
2.当c < V / w时, 可转化为放物品的数量为1、2、3……c个,即转化为01背包求解。
但是上面这种方法的时间复杂度为O(V连加M),其中M为数量。这个复杂度是很大的,可以用二进制拆分优化一下。
二进制拆分:任何数num都可以拆分为2^k的加和的形式,即:
num = 2^k1 + 2^k2 + …… + 2^kn (其中kn可以取任意非负整数)
这样上面的第二种情况就可以利用这种方法进行优化,使遍历从1、2、3……c优化到1、2、4……2^k,时间复杂度为O(V连加logM)。这种优化程度就可以应对大部分题目了。(当然,对于一些卡时间的题目也不行,需要优先队列优化)。
还有一点,看懂这一点就能看懂二进制优化的核心了。
对于使用二进制拆分成的一组数字:1、2、4、8……,这些数字之间缺少3、5、6、7这样的数字,在遍历的时候没有遍历他们,因为这些数字可以由前面遍历过的数字拼凑合成。比如,3可以由1和2合成,5可以由1和4合成,以此类推。还有,比如,如果最终结果包含5,那在遍历的时候就可能记录1和4,也就是说最终结果是1和4这两件被拆分的物品,最后合到一起就是5了。
就是这种方法,使不用被遍历的数字也能出现在过程中,这就是二进制优化的精髓!
以下为程序流程:
void MultiplePack(int w, int p, int m)
{
if (w * m >= p)
{
CompletePack(w, p);
return;
}
int k = 1;
while (k < m)
{
ZeroOnePack(k * w, k * p);
m -= k;
k *= 2;
}
ZeroOnePack(m * w, m * p);
}
下面附上多重背包的模板:
#include <iostream>#include <algorithm>using namespace std;#define MAXL 10001int dp[MAXL], V, n, w, p, m;void ZeroOnePack(int w, int p);void CompletePack(int w, int p);void MultiplePack(int w, int p, int m);int main(){cin >> V >> n;for (int i = 1; i <= n; i++){cin >> w >> p >> m;MultiplePack(w, p, m);}cout << dp[V] << endl;return 0;}void MultiplePack(int w, int p, int m){if (w * m >= p){CompletePack(w, p);return;}int k = 1;while (k < m){ZeroOnePack(k * w, k * p);m -= k;k *= 2;}ZeroOnePack(m * w, m * p);}void ZeroOnePack(int w, int p){for (int j = V; j >= w; j--)dp[j] = max(dp[j - w] + p, dp[j]);}void CompletePack(int w, int p){for (int j = w; j <= V; j++)dp[j] = max(dp[j - w] + p, dp[j]);}
0 0
- 浅谈多重背包
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- 【多重背包】
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- 多重背包
- Nodejs之旅开始
- hadoop2.2.0 centos 编译安装详解
- Unity3D中Awake和Start方法的区别
- 计算机是如何工作的?
- 6-17复数四则运算
- 浅谈多重背包
- bat注册tomcat加载指定jdk
- DRP-ThreadLocal简单理解
- javascript属性访问表达式
- 第一章 3
- meteor
- 背包问题_模板
- 运行wordcount 导入FileUtil.java文件出现错误解决办法
- POJ 2288 Islands and Bridges(状压dp)