(  推荐 : http://blog.csdn.net/insistgogo/article/details/11081025 )

问题描述 : 已知一个容量为 V 的背包 和 N 件物品 , 第 i 件物品的价值是 value[ i ] 体重为 weight[ i ]  。

条件 : 每件物品有无限多个 , 能放多少就放多少 。

问题 : 在不超过背包容量的前提下 , 问最多能获得的最大收益 。

基本思路 : 直接扩展01背包

  区别于 01背包 , 完全背包中的物品可以放入0件 、 1件 、 2件 ... , 所以就可以写这样的状态转移方程 。

dp[j] = max ( dp[j] , dp[j-k*weight[i]]+k*value[i] ) ;  k <= v / weight[i]

  

  这样写的意思是 , 同 01背包一样 , 我遍历所有物品 , 在每个物品下遍历所有体积 ,  完全背包只需要在加一点就是在每种物品的每个体积下,我在遍历所有可能该种物品可以放多少个 。

给出完整的代码 :

  

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std ;
#define Max(a,b) a>b?a:b int weight[10] ;
int value[10] ;
int dp[100] ; int main ( ) {
int n , v ; cin >> n >> v ;
for ( int i = 1 ; i <= n ; i++ )
cin >> weight[i] >> value[i] ; for ( int i = 1 ; i <= n ; i++ ) {
for ( int j = v ; j >= weight[i] ; j-- ) {
for ( int k = 1 ; k <= v/weight[i] ; k++ ) {
dp[j] = Max ( dp[j] , dp[j-k*weight[i]]+k*value[i] ) ;
}
}
} cout <<dp[v] ;
return 0 ;
}

  

代码优化 :

  完全背包有一种很简单有效的优化 , 两件物品 重量 为 we[i] , we[j] , 价值为va[i] , va[j] 。若we[i] < w[j] ,并且 va[i] > va[j] , 则将物品 j 去掉 , 不用考虑 。但我觉得这样做的话还是不太好 , 虽然没在网上找到反例 。

转化为01背包求解 :

  对于每件物品 , 背包最多能装的件数是  v / weight[i] , 因此就可以进行一个预处理 , 增加所有可以增加的物品 , 直到每种物品的数量都达到 v / weight[i] 。此时在看这个问题 , 就可以完全转变为 01 背包 。

时间复杂度的分析:O(NNew*V),其中V表示扩展前背包容量,NNew表示扩展后物品的个数,NNew = Σ(V/Weight[i](向下取整))

对物品拆分 , 拆成 2 进制的形势

  具体思路:把第i种物品拆成费用为weight[i]*2^k、价值为w[i]*2^k的若干件物品,其中k满足weight[i]*2^k<=V。

  二进制思想 : 因为不管最优策略选几件第 i 件物品 , 总可以表示成若干个 2^k 的和 。

盗的代码 , 表示还不会写 :

  

    #include <iostream>
#include <vector>
#include <assert.h>
using namespace std;
/*
f[v]:表示第i件物品放入容量为v的背包后,获得的最大容量
f[v] = max(f[v],f[v - weight[i]] + value[i]);
初始条件:f[0] = 0;
*/ const int N = 3;
const int V = 20;//5
int weight[N + 1] = {0,3,2,2};
int Value[N + 1] = {0,5,10,20}; int NNew = 0;
vector<int> weightVector;
vector<int> Valuevector;
int f[V + 1] = {0};
/*拆分物品*/
void SplitItem()
{
//从1开始
weightVector.push_back(0);
Valuevector.push_back(0);
//开始拆分
int nPower = 1;
for (int i = 1;i <= N;i++)
{
nPower = 1;
while (nPower * weight[i] <= V)
{
weightVector.push_back(nPower * weight[i]);
Valuevector.push_back(nPower * Value[i]);
nPower <<= 1;
}
}
} int Completeknapsack()
{
//拆分物品
SplitItem();
//转化为01背包处理
NNew = weightVector.size() - 1;//多加了一个0,要减去 for (int i = 1;i <= NNew;i++)//物品个数变化
{
for (int v = V;v >= weightVector[i];v--)//背包容量仍是V
{
f[v] = max(f[v],f[v - weightVector[i]] + Valuevector[i]);
}
} return f[NNew];
}
int main()
{
cout<<Completeknapsack()<<endl;
system("pause");
return 1;
}

(N * V 的算法)

  在完全背包中,v变化的区间是顺序循环的原因:完全背包的特点是每种物品可选无限件,在求解加选第i种物品带来的收益f[i][v]时,在状态f[i][v-c[i]]中已经尽可能多的放入物品i了,此时在f[i][v-c[i]]的基础上,我们可以再次放入一件物品i,此时也是在不超过背包容量的基础下,尽可能多的放入物品i。

  代码示例 :

 

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std ;
#define Max(a,b) a>b?a:b int weight[10] ;
int value[10] ;
int dp[100] ; int main ( ) {
int n , v ; cin >> n >> v ;
for ( int i = 1 ; i <= n ; i++ )
cin >> weight[i] >> value[i] ; for ( int i = 1 ; i <= n ; i++ ) {
for ( int j = weight[i] ; j <= v ; j++ ) {
dp[j] = Max ( dp[j] , dp[j-weight[i]]+value[i] ) ; // 对于每件物品 , 在不超背包体积的前提下 , 尽可能多的放
}
} cout <<dp[v] ;
return 0 ;
}

dp-完全背包的更多相关文章

  1. USACO Money Systems Dp 01背包

    一道经典的Dp..01背包 定义dp[i] 为需要构造的数字为i 的所有方法数 一开始的时候是这么想的 for(i = 1; i <= N; ++i){ for(j = 1; j <= V ...

  2. 树形DP和状压DP和背包DP

    树形DP和状压DP和背包DP 树形\(DP\)和状压\(DP\)虽然在\(NOIp\)中考的不多,但是仍然是一个比较常用的算法,因此学好这两个\(DP\)也是很重要的.而背包\(DP\)虽然以前考的次 ...

  3. HDOJ(HDU).2844 Coins (DP 多重背包+二进制优化)

    HDOJ(HDU).2844 Coins (DP 多重背包+二进制优化) 题意分析 先把每种硬币按照二进制拆分好,然后做01背包即可.需要注意的是本题只需要求解可以凑出几种金钱的价格,而不需要输出种数 ...

  4. HDOJ(HDU).1059 Dividing(DP 多重背包+二进制优化)

    HDOJ(HDU).1059 Dividing(DP 多重背包+二进制优化) 题意分析 给出一系列的石头的数量,然后问石头能否被平分成为价值相等的2份.首先可以确定的是如果石头的价值总和为奇数的话,那 ...

  5. HDOJ(HDU).2191. 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (DP 多重背包+二进制优化)

    HDOJ(HDU).2191. 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (DP 多重背包+二进制优化) 题意分析 首先C表示测试数据的组数,然后给出经费的金额和大米的种类.接着是每袋大米的 ...

  6. HDOJ(HDU).4508 湫湫系列故事――减肥记I (DP 完全背包)

    HDOJ(HDU).4508 湫湫系列故事――减肥记I (DP 完全背包) 题意分析 裸完全背包 代码总览 #include <iostream> #include <cstdio& ...

  7. HDOJ(HDU).1284 钱币兑换问题 (DP 完全背包)

    HDOJ(HDU).1284 钱币兑换问题 (DP 完全背包) 题意分析 裸的完全背包问题 代码总览 #include <iostream> #include <cstdio> ...

  8. HDOJ(HDU).1114 Piggy-Bank (DP 完全背包)

    HDOJ(HDU).1114 Piggy-Bank (DP 完全背包) 题意分析 裸的完全背包 代码总览 #include <iostream> #include <cstdio&g ...

  9. HDOJ(HDU).3466 Dividing coins ( DP 01背包 无后效性的理解)

    HDOJ(HDU).3466 Dividing coins ( DP 01背包 无后效性的理解) 题意分析 要先排序,在做01背包,否则不满足无后效性,为什么呢? 等我理解了再补上. 代码总览 #in ...

  10. POJ.3624 Charm Bracelet(DP 01背包)

    POJ.3624 Charm Bracelet(DP 01背包) 题意分析 裸01背包 代码总览 #include <iostream> #include <cstdio> # ...

随机推荐

  1. uni-app 常用框架内置方法 更新中 .....

    获取 登录信息,getStorage 初始化页面数据   请求  下拉刷新页面 加载更多  点击跳转  个人中心  uni.request(OBJECT)   success=成功    fail=失 ...

  2. Spring security用户URL权限之FilterSecurityInterceptor

    总: 用户通过浏览器发送URL地址,由FilterSecurityInterceptor判断是否具有相应的访问权限. 对于用户请求的方法权限,例如注解@PreAuthorize("hasRo ...

  3. php框架thinkphp3.2.3 配置文件bug

    bug:有前后台的项目部署阶段(DEBUG模式为false)中,修改应用配置文件后,无效,修改自定义配置文件,正常;(开发模式正常) //项目只有后台没有前台的(单独模块),直接写在模块配置中即可,不 ...

  4. 四叶草(css)

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <style> . ...

  5. 用webAudio和canvas实现音频可视化

    前两天遇到了要显示音频波形图的需求,因为时间紧,就直接用了wavesufer.js,这两天有空,就研究了一下怎么用webAudio实现音频的可视化. 大致流程是对音源进行解析,解析得到的数据是个频谱数 ...

  6. Vue中通过属性绑定为元素绑定style行内样式

    1.直接在元素上通过:style的形式,书写样式对象 2.将样式对象定义在data中,并直接引用到:style中 3.在:style中通过数组,引用多个data上的样式对象

  7. margin为负值的几种情况

    1.margin-top为负值像素 margin-top为负值像素,偏移值相对于自身,其后元素受影响,见如下代码: 1 <!DOCTYPE html> 2 <html lang=&q ...

  8. dotnet 控制台读写 Sqlite 提示 no such table 找不到文件

    在使用 dotnet 读写 Sqlite 可以通过 EF Core 的方法,但是在 EF Core 创建的数据库可能和读写的数据库不是相同的文件 在我运行代码的时候发现在通过迁移创建数据库,创建的文件 ...

  9. nor flash之频率限制

    背景 支持一款nor flash时,出于性能考虑,一般会查看其nor支持的最高频率以及主控端spi控制器的最高频率,以选择一个合适的运行频率. 对于一款主控支持多款flash的情况,还得考虑好兼容性等 ...

  10. 程序员必须掌握的性能调优 X Y Z

    热评博文:<如何设计出优美的Web API?>,现阅读量超 2500,小伙伴们不要错过哦! 2003 ~ 2008 年,这五年老兵哥我在通信行业做实习生和开发岗,主要用 C / C++ / ...