hdu2191 多重背包

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

多重背包:有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。

              求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

有两种思路,其中一种是转换为01背包,还有一种就是转换为01背包和完全背包。

转换为01背包代码:

//转换为01背包的代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=105;
const int MAXW=4005;
int v[N],w[N],num[N];
int dp[MAXW];

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=0; i<m; i++)
            cin>>w[i]>>v[i]>>num[i];
        memset(dp,0,sizeof(dp));
        for(int i=0; i<m; i++)
            for(int j=1; j<=num[i]; j++)
                for(int k=n; k>=w[i]; k--)
                    dp[k]=max(dp[k],dp[k-w[i]] +v[i]);
        cout<<dp[n]<<endl;
    }
    return 0;
}

 

多重背包转换成完全背包和01背包:

0--N中的任何一个数都可以用N的二进制的位数个数表示,这些数分别是1....1<<i   untile 1<<i   < N  && 1<<(i+1) >N  另外一个是N-前面所有二进制数的总和。

所以多重背包转换成完全背包和01背包的过程中01背包的部分可以用二进制优化。 

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long

int p[205],w[205],c[205];
int dp[105];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=m; i++)
            cin>>p[i]>>w[i]>>c[i];
        memset(dp,0,sizeof(dp));
        for(int i=1; i<=m; i++)
        {
            if(p[i]*c[i]>m)
            {
                for(int j=p[i]; j<=n; j++)
                    dp[j]=max(dp[j],dp[j-p[i]]+w[i]);
            }
            else
            {
                int k=1;
                for(int j=1; c[i]>0; j<<=1)
                {
                    int temp=min(j,c[i]);
                    for(int q=n; q>=temp*p[i]; q--)
                        dp[q]=max(dp[q],dp[q-p[i]*temp]+w[i]*temp);
                    c[i]-=j;
                }
            }
        }
        cout<<dp[n]<<endl;
    }
    return 0;
}

 


 

posted @ 2016-10-12 17:43  a_clown_cz  阅读(190)  评论(0)    收藏  举报