背包3

Time Limit: 2000/1000ms (Java/Others)

Problem Description:

有n种(每一种有无数个)重量和价值分别为Wi,Vi的物品,现从这些物品中挑选出总量不超过W的物品,求所有方案中价值总和的最大值。

Input:

输入包含多组测试用例,每一例的开头为两位整数 n、W(1<=n<=10000,1<=W<=1000),接下来有 n 行,每一行有两位整数 Wi、Vi(1<=Wi<=10000,1<=Vi<=100)

Output:

输出为一行,即所有方案中价值总和的最大值。

Sample Input:

3 4
1 2
2 5
3 7
3 5
2 3
3 4
4 5

Sample Output:

10
7
解题思路:简单的完全背包。和01背包一样,dp[i][j]表示从前i种物品中挑选总重量不超过j时总价值的最大值。
易得状态转移方程:dp[i,j]=max(dp[i-1,j-k*wi]+k*vi)(0<=k*wi<=W),其中dp[i-1,j-k*wi]+k*vi表示前i-1种物品中选取若干件物品放入剩余容量为j-k*wi的背包中所能得到的最大价值加上k件第i种物品。很明显,多了一个参数k,时间复杂度变为O(nW∑(W/wi)),可知这样的时间复杂度是很大的,我们必须找到更优的办法。
因为在dp[i,j]的计算中选择k(k>=1)个物品得到的最大价值与在dp[i][j-wi](背包中已包含至少一件第i种物品)的计算中选择k-1个物品得到的最大价值是相同的,所以dp[i][j]的递推中k>=1部分的计算已经在dp[i][j-wi]的计算中完成了。那么有如下推导过程:
dp[i,j-wi]=max(dp[i-1,j],dp[i-1,(j-wi)-(k-1)*wi]+(k-1)*vi)(k>=1,dp[i-1,j]表示第i种物品一件都不选)
=max(dp[i-1,j],dp[i-1,j-k*wi]+(k-1)*vi)(k>=1,表示当前背包中至少含有一件第i种物品)
dp[i,j]=max(dp[i-1,j],dp[i-1,j-k*wi]+k*vi)(k>=1)
    =max(dp[i-1,j],dp[i,j-wi]+vi)
于是成功地把参数k给消掉了,现在的时间复杂度和01背包一样都为O(nW)。
怎么理解上面的状态转移方程呢?①如果第i件物品一件都不取,显然dp[i,j]=dp[i-1,j];②如果要取,那么当前背包中至少已含有一件第i种物品(即j至少已含有一个wi),则dp[i,j]=dp[i,j-wi]+vi。因为01背包中每个物品只有一件,在放入第i件物品时需考虑到前i-1件物品放入剩余背包容量为j-wi得到的最大价值,但是现在每个物品拥有无限件,即无需考虑前i-1个物品了,所要考虑的就是当前容量下能否再放入一件第i种物品,而dp[i,j-wi]已确保dp[i,j]中至少有一件第i种物品,所以要预留wi的背包容量再来存放一件第i种物品,这样就实现了一个物品可以取多件的操作。
同样地,完全背包空间也可以优化到O(W)。怎么实现呢?只需将01背包第二重循环正序枚举即可。为什么呢?通过模拟过程可以发现,正序使得一个物品可以被取多次。因为01背包中按照W递减来循环是为了保证第i次循环中的状态dp[i,j]是由状态dp[i-1,j-wi]递推而来,换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果dp[i−1,j−wi]。而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果dp[i,j-wi],所以就可以并且必须采用wi~W递增的顺序循环。
一维滚动数组状态转移方程:dp[j]=max(dp[j],dp[j-w[i]]+v[i])。
AC代码一:(二维数组实现)
 #include<bits/stdc++.h>
using namespace std;
int n,W,v[],w[],dp[][];
int main(){
while(cin>>n>>W){
for(int i=;i<=n;++i)cin>>w[i]>>v[i];
memset(dp,,sizeof(dp));
for(int i=;i<=n;++i){
for(int j=;j<=W;++j){
if(j<w[i])dp[i][j]=dp[i-][j];//当前容量j容纳不下一件第i种物品
else dp[i][j]=max(dp[i-][j],dp[i][j-w[i]]+v[i]);//再拿一件第i种物品和一件都不拿的情况比一下
}
}
cout<<dp[n][W]<<endl;
}
return ;
}
AC代码二:(一维数组实现)
 #include<bits/stdc++.h>
using namespace std;
int n,W,v[],w[],dp[];
int main(){
while(cin>>n>>W){
for(int i=;i<n;i++)
cin>>w[i]>>v[i];
memset(dp,,sizeof(dp));
for(int i=;i<n;++i) //种类
for(int j=w[i];j<=W;++j) //重量从小到大枚举
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
cout<<dp[W]<<endl;
}
return ;
}

ACM_完全背包的更多相关文章

  1. ACM_物品分堆(01背包)

    物品分堆 Time Limit: 2000/1000ms (Java/Others) Problem Description: 有n个物品,物品i的重量为Wi,现在想要把这个n个物品分类两堆,求最小的 ...

  2. ACM_寒冰王座(完全背包)

    寒冰王座 Time Limit: 2000/1000ms (Java/Others) Problem Description: 不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票) ...

  3. nyist oj 311 全然背包 (动态规划经典题)

    全然背包 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描写叙述 直接说题意,全然背包定义有N种物品和一个容量为V的背包.每种物品都有无限件可用.第i种物品的体积是c,价值是 ...

  4. NYOJ 311 完全背包

    完全背包 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用.第i种物品的体积是c,价值是 ...

  5. 【USACO 3.1】Stamps (完全背包)

    题意:给你n种价值不同的邮票,最大的不超过10000元,一次最多贴k张,求1到多少都能被表示出来?n≤50,k≤200. 题解:dp[i]表示i元最少可以用几张邮票表示,那么对于价值a的邮票,可以推出 ...

  6. HDU 3535 AreYouBusy (混合背包)

    题意:给你n组物品和自己有的价值s,每组有l个物品和有一种类型: 0:此组中最少选择一个 1:此组中最多选择一个 2:此组随便选 每种物品有两个值:是需要价值ci,可获得乐趣gi 问在满足条件的情况下 ...

  7. HDU2159 二维完全背包

    FATE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  8. CF2.D 并查集+背包

    D. Arpa's weak amphitheater and Mehrdad's valuable Hoses time limit per test 1 second memory limit p ...

  9. UVALive 4870 Roller Coaster --01背包

    题意:过山车有n个区域,一个人有两个值F,D,在每个区域有两种选择: 1.睁眼: F += f[i], D += d[i] 2.闭眼: F = F ,     D -= K 问在D小于等于一定限度的时 ...

随机推荐

  1. Ubuntu 16.04下SecureCRT无法输入中文的解决思路

    说明:首先网上的方法基本都是不行的,别试了. 但是可以有弥补方案: 1.通过外界的软件编辑好中文,然后粘贴过去.虽然是多了一步,但是也可以输入中文. 2.关于这个问题应该是没有中文字体库导致的,可以尝 ...

  2. 百万级 TCP 长连接即时通讯框架 t-io

    原文:http://www.t-io.org:9292/ https://www.oschina.net/p/t-io

  3. Windows下如何查看当前登录用户

    1.通过whoami命令查看 2.通过username变量查看,具体命令如下:echo %username% 上述两种方法只能查看当前会话用户信息,那么如何看到其他登录用户呢? 可以通过执行query ...

  4. CentOS 5.11开启VNC Service

    1.     #yum install vncserver 2.     #vncpasswd       此密码将成为vnc的login password          password:    ...

  5. swift学习笔记(四)关于类的继承

    在swift中,继承是区分类与其它对象的基本特征 继承后的子类能够重写父类的方法,包含类方法和实例方法,属性和附属脚本(subscript) 在继承过程中,构造器方法init()是不被继承的,须要显示 ...

  6. Ckeditor通过Ajax更新数据

    之前在表单中对ckeditor的赋值就直接是 $("#theadEditor").val(result); 而如今我想通过点击不同选项来使用Ajax在后台訪问数据.对ckedito ...

  7. Cocos2d-X中的ProgressTimer

     ProgressTimer即进度条,进度条在游戏开发中运用很广泛,比如在一些格斗游戏中,显示血液的变化,还有游戏载入进度,等都离不开进度条 Cocos2d-X中使用CCProgressTimer ...

  8. Android 5.1 Settings源代码简要分析

    转载请注明出处,谢谢~http://blog.csdn.net/u011974987/article/details/51004854. 概述: 先声明:本人工作快两年了,仍是菜鸟级别的.羞愧啊!曾经 ...

  9. 【c语言】统计一个数字在排序数组中出现的次数

    // 题目:统计一个数字在排序数组中出现的次数. //  比如:排序数组{1.2,3,3,3,3,4.5}和数字3,因为3出现了4次.因此输出4 有一种最简单的算法,遍历.可是有比它效率更高的 先看遍 ...

  10. 编程算法 - 最小的k个数 代码(C)

    最小的k个数 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入n个整数, 找出当中的最小k个数. 使用高速排序(Quick Sort)的方法 ...