DP之多重背包

Description

给定N种物品和一个容量为C的背包,第i种物品最多有 Mi 件可用,每件的重量是Wi,价值是Vi。问:将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

Input

输入的第一行为测试样例的个数T,接下来有T个测试样例。

每个测试样例的第一行是物品种数N(1 ≤ N ≤ 100)和背包容量CC ≤ 10000)。

接下来N行,每行三个正整数,Wi ,Vi 和 M( Wi ≤ 10000,    Vi ≤ 10000,    Mi ≤ 10000 ),分别表示第i种物品的重量 Wi ,价值 Vi ,及个数 Mi 。

Output

对应每个测试样例输出一行,只有一个整数,表示装入背包的物品总价值的最大值。

Sample Input

1
2 8
4 100 2
2 100 4

Sample Output

400


代码如下:

#include<cstdio>///oj1943
#include<algorithm>
#include<cstring>
using namespace std;
const int MAX=20000;
int dp[MAX],w[MAX],v[MAX];
int main()
{
    int n,c,ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%d%d",&n,&c);
        int weigh,value,times;
        int sum=1;
        for(int i=1;i<=n;i++){
        scanf("%d%d%d",&weigh,&value,×);
        for(int j=1;j<=times;j<<=1)///二进制处理times,将一个背包分成多个(可取次数为1的)背包
        {
            w[sum]=j*weigh;
            v[sum++]=j*value;
            times-=j;
        }
        if(times>0){
            w[sum]=times*weigh;
            v[sum++]=times*value;
        }
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<sum;i++)///这里的和01背包没什么区别
        {
            for(int j=c;j>=w[i];j--)
                dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
        printf("%d\n",dp[c]);
    }
    return 0;
}

这里还可用深搜解决:

#include<cstdio>///深搜
#include<algorithm>
#include<cstring>
using namespace std;
int num[7],flag,sum;
void dfs(int S,int tot)
{
    if(S==sum){
        flag=1;return;
    }
    if(flag==1) return;
    for(int i=6;i>0;i--)///相当于枚举,从最后开始,假设num[i]有n个,那么会递归调用开辟n个空间,每个空间的S值为
    {                  ///从小到大i,2*i,3*i......k*i(1<=k<=n,k*i<=sum)),紧接着又在每个空间跟num[i-1]类似上面的递归调用
        if(num[i]>=1){///在递归过程中只要S的值==sum,就一直返回就好了,很暴力
            if(S+i<=sum) {
                num[i]--;
            dfs(S+i,i);
            if(flag==1) return;
            }
        }
    }
    return;
}
int main()
{
    int ncase=0;
    while(1)
    {
        ncase++;
         sum=0;
        for(int i=1;i<=6;i++){
            scanf("%d",&num[i]);
            sum+=num[i]*i;
        }
        if(sum==0) break;
        printf("Collection #%d:\n",ncase);
        if(sum%2){
            printf("Can't be divided.\n\n");continue;
        }
        sum/=2;///注意除以2
        flag=0;
        dfs(0,6);
        if(flag) printf("Can be divided.\n\n");
        else printf("Can't be divided.\n\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ljd201724114126/article/details/80445557