hdu 2191 多重背包
题目链接:hdu 2191
题意很明显,数据规模也比较小,不过这题的数据还是很强的,多重背包我之前一直没有了解透切,所以也 wa 了不知多少次了,先来个朴素的比较暴力的版本:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define sd(x) scanf("%d",&(x)) 6 #define sd2(x,y) scanf("%d %d",&(x),&(y)) 7 #define sd3(x,y,z) scanf("%d %d %d",&(x),&(y),&(z)) 8 9 int dp[103][103]; 10 11 int main() { 12 int t,n,m,p,h,c; 13 sd(t); 14 while(t--) { 15 sd2(n,m); 16 memset(dp, 0, sizeof(dp)); 17 for(int i = 1; i <= m; ++i) { 18 sd3(p,h,c); 19 for(int k = 0; k <= c; ++k) 20 for(int j = k * p; j <= n; ++j) 21 dp[i][j] = max(dp[i][j], dp[i - 1][j - k * p] + k * h); 22 } 23 printf("%d\n",dp[m][n]); 24 } 25 return 0; 26 }
可以用滚动数组,不过只是得是 dp[2][103] 这样的至少两行数组,而不能是 dp[103] 的一行,因为在读入 p, h, c 后有两个循环的,因此 dp[i-1][j-k*p] 的值就会被多次用到,不能像简单的 01背包、完全背包那样一个循环之后就被会覆盖掉,就是因为这个问题 wa 了好几次,唉,都是模板记得太熟了。
然后,我看了背包九讲后,发现多重背包还是能作优化的:
按照他说的我写了下程序,也能AC,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define sd(x) scanf("%d",&(x)) 6 #define sd2(x,y) scanf("%d %d",&(x),&(y)) 7 #define sd3(x,y,z) scanf("%d %d %d",&(x),&(y),&(z)) 8 9 int dp[103]; 10 11 int main() { 12 int t,n,m,p,h,c; 13 sd(t); 14 while(t--) { 15 sd2(n,m); 16 memset(dp, 0, sizeof(dp)); 17 while(m--) { 18 sd3(p,h,c); 19 if(p * c >= n /*&& 0*/) { // 完全背包这部分其实并不是必须的,一样可以 AC 20 for(int j = p; j <= n; ++j) 21 dp[j] = max(dp[j], dp[j - p] + h); 22 } 23 else { 24 int k = 1; 25 while(k <= c) { // 对转换后的每种物品用 01 背包来实现 26 for(int j = n; j >= p * k; --j) 27 dp[j] = max(dp[j], dp[j - p * k] + h * k); 28 c -= k; 29 k <<= 1; 30 } 31 if(c) // 最后作判断一下 32 for(int j = n; j >= p * c; --j) 33 dp[j] = max(dp[j], dp[j - p * c] + h * c); 34 } 35 } 36 printf("%d\n",dp[n]); 37 } 38 return 0; 39 }