POJ-1276 多重背包问题

来源:互联网 发布:imovie的windows版 编辑:程序博客网 时间:2024/06/05 13:35

Cash Machine

    题意:输入第一行cash  N n1 D1 n2 D2 ... nN DN ,D1表示一种面值的零钱,n1表示D1可以使用的数量。一共有N种零钱。需要找出用这些零钱可以组成的不超过cash的最大数额。

    这是一道多重背包的问题,和poj-1014 多重背包问题类似,需要先转化成01背包,再用01背包问题的方法求解。转换的代码如下,a[i]是转换前第i个零钱的数量,b[i]是转换前第i个零钱的面值,w[count]是转换后的第count个零钱的面值,转换后每种零钱只有一个,但是可以组合成转换前的各种组合。

int count = 1;for(int i=1;i<=n;i++){int c=1;while(a[i]-c>0){w[count++] = c*b[i];a[i] -= c;c = c << 1;}w[count++] = a[i]*b[i];}

    之后用01背包的方法计算,因为没有背包问题中体积这一参数,可以将体积设置为与价格一致。状态转移方程为dp[j] = max(dp[j],dp[j-w[i]]+w[i]),用一维数组来表示需要从后往前变化,每一行已经扫描到的部分属于第i行,未扫描到的部分属于第i-1行,j表示第j列。代码如下:

for( i=1;i<count;i++){for(int j=all;j>=w[i];j--){dp[j] = max(dp[j],dp[j-w[i]]+w[i]);}}

    完整的AC代码如下:

#include<iostream>#include<cstring>#include<math.h>using namespace std;int all,n;int a[210],b[210],w[210],dp[110000];void dp_fun(){//多重变换为01背包 memset(dp,0,sizeof(dp));int count = 1;for(int i=1;i<=n;i++){int c=1;while(a[i]-c>0){w[count++] = c*b[i];a[i] -= c;c = c << 1;}w[count++] = a[i]*b[i];}int i;for( i=1;i<count;i++){for(int j=all;j>=w[i];j--){dp[j] = max(dp[j],dp[j-w[i]]+w[i]);}}cout << dp[all]<<endl;} int main(){while(cin >> all){cin >> n;for(int i=1;i<=n;i++){cin >> a[i] >> b[i];}dp_fun();}return 0;}


原创粉丝点击