hdoj 2191 多重背包入门题

来源:互联网 发布:漫画上色软件 编辑:程序博客网 时间:2024/05/07 03:55

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2191

该题目为裸的多重背包 入门题。。纯粹用来检测自己对背包九讲的理解。。

结果WA了居然因为忘记了多组数据的循环语句。。果然太久没写,写的越来越渣。。

此处采用的第一种方法为转化为01背包问题,并没有进行优化。。

状态转移方程为F[i ,v] = max {F[i − 1,v − k ∗ C i ] + k ∗ W i | 0 ≤ k ≤ M i }

然后我们依然可以转化为一维数组来进行求解。。。

此处附上该方法的代码:

#include<iostream>#include<cstring>using namespace std;int c[110];int w[110];int m[110];int dp[110];int max(int a,int b){return (a>b)?a:b;}int main (){int t,n,V;cin >> t;while(t--){memset(dp,0,sizeof(dp));cin >> V >> n;for(int i = 1;i <= n;i++)cin >> c[i] >> w[i] >> m[i];for(int i = 1;i <= n;i++){for(int j = V;j >= c[i];j--){for(int k = 1;k <= m[i] && k*c[i] <= j;k++)  //保证 k不超过该物品的个数,且花费不能超过经费 dp[j] = max(dp[j],dp[j-k*c[i]]+k*w[i]);}}cout << dp[V] << endl;}return 0;}
然后一种方法是转化成二进制的方法。背包九讲中时这样说的:

仍然考虑二进制的思想,我们考虑把第 i 种物品换成若干件物品,使得原问
题中第 i 种物品可取的每种策略——取 0...M i 件——均能等价于取若干件代换
以后的物品。另外,取超过 M i 件的策略必不能出现。
方法是:将第 i 种物品分成若干件01背包中的物品,其中每件物品有一个系
数。这件物品的费用和价值均是原来的费用和价值乘以这个系数。令这些系数
分别为 1,2^2,2^3 , ...2 k−1 ,M i − 2 k + 1 ,且 k 是满足 M i − 2 k + 1 > 0 的最大整数。例
如,如果 M i 为 13 ,则相应的 k = 3 ,这种最多取 13 件的物品应被分成系数分别
为 1,2,4,6 的四件物品。
分成的这几件物品的系数和为 M i ,表明不可能取多于 M i 件的第 i 种物品。另
外这种方法也能保证对于 0...M i 间的每一个整数,均可以用若干个系数的和表
示。这里算法正确性的证明可以分 0...2 k−1 和 2 k ...M i 两段来分别讨论得出,
希望读者自己思考尝试一下。

伪代码如下:

def MultiplePack( F , C , W , M )
if C · M ≥ V
CompletePack( F , C , W )
return
k := 1
while k < M
ZeroOnePack( kC , kW )
M := M − k
k := 2k
ZeroOnePack( C · M , W · M )

思考了一下感觉伪代码中的拆分方式并不是跟前文的一样,,伪代码中是将背包中的拆分成 1,2^2,2^3,....2^k, m - 2^k,   且k是满足m - 2^k > 0 的最大整数。。

这样不管拿几个该物品也可以将所有方式都表示出来,所以应该是一样的。。

于是将该方法实现了一下。。

代码如下:

#include<iostream>#include<cstring>using namespace std;int w[110];int c[110];int m[110];int dp[110];int max(int a,int b){return (a>b) ? a:b;}int main (){int t,n,V;cin >> t;while (t--){memset(dp,0,sizeof(dp));cin >> V >> n;for(int i = 1;i <= n;i++)cin >> c[i] >> w[i] >> m[i];for(int i = 1;i <= n;i++){if(c[i]*m[i] >= V){for(int j = c[i];j <= V;j++)dp[j] = max(dp[j],dp[j-c[i]]+w[i]); }else {int k = 1;while (k < m[i]){for(int j = V;j >= k*c[i];j--)dp[j] = max(dp[j],dp[j-k*c[i]]+k*w[i]);m[i] = m[i] - k;k = 2*k;}for(int j = V;j >= c[i]*m[i];j--)  //此为拆到最后的那个 m - 2^k的物品 dp[j] = max(dp[j],dp[j-m[i]*c[i]] + m[i]*w[i]); }}cout << dp[V] << endl;}return 0;}


0 0