Acwing:混合背包

题目链接:

有 N 种物品和一个容量是 V 的背包。

物品一共有三类:

第一类物品只能用1次(01背包);
第二类物品可以用无限次(完全背包);
第三类物品最多只能用 si 次(多重背包);
每种体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。

si=1 表示第 i 种物品只能用1次;
si=0 表示第 i 种物品可以用无限次;
si>0 表示第 i 种物品可以使用 si 次;
输出格式
输出一个整数,表示最大价值。

数据范围
0<N,V≤1000
0<vi,wi≤10001≤si≤1000
输入样例
4 5
1 2 -1
2 4 1
3 4 0
4 5 2
输出样例:
8

题解:

将多重背包拆分为01背包,然后进行完全背包和01背包操作即可

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e3+5;
int dp[maxn],v[maxn],w[maxn],s[maxn],num[maxn],va[maxn],k[maxn];
int main()
{
    int n,V;
    cin>>n>>V;
    for(int i=1; i<=n; i++)
        cin>>v[i]>>w[i]>>s[i];
    int cnt=0;
    for(int i=1; i<=n; i++)
    {
        if(s[i]<0)
        {
            num[++cnt]=v[i],va[cnt]=w[i],k[cnt]=1;
        }
        else if(s[i]>0)
        {
            for(int j=1; j<=s[i]; j=j<<1)
            {
                num[++cnt]=j*v[i];
                va[cnt]=j*w[i];
                k[cnt]=1;
                s[i]-=j;
            }
            if(s[i]>0)
            {
                num[++cnt]=s[i]*v[i];
                va[cnt]=s[i]*w[i];
                k[cnt]=1;
            }
        }
        else if(s[i]==0)
        {
            num[++cnt]=v[i],va[cnt]=w[i],k[cnt]=0;
        }
    }
    for(int i=1; i<=cnt; i++)
    {
        if(k[i])
        {
            for(int j=V; j>=num[i]; j--)
                dp[j]=max(dp[j],dp[j-num[i]]+va[i]);
        }
        else
        {
            for(int j=num[i]; j<=V; j++)
                dp[j]=max(dp[j],dp[j-num[i]]+va[i]);
        }
    }
    cout<<dp[V]<<endl;
}
发布了254 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yangzijiangac/article/details/104629622