动态规划-分组背包问题

https://vjudge.net/contest/297216?tdsourcetag=s_pctim_aiomsg#problem/K

3(物品组数) 3(时间)

f[i,j]表示完成了前i件任务,
背包容量为j时所能达到的最大价值。
f[i-1,j-cost]+val;
2 1 最多选一件
2 5
3 8

2 0 至少选一件
1 0
2 1

3 2 自由选
4 3
2 1
1 1

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int INF=0x3f3f3f3f;
const int maxn=105;
int cost[maxn];
int val[maxn];
int f[maxn][maxn];
int main()
{
    int m,t;
    while(scanf("%d%d",&m,&t)==2) // 不写==2会超时!!
    {
        memset(f,0,sizeof(f));
        for(int i=1; i<=m; i++)
        {
            int n,type;
            scanf("%d%d",&n,&type);
            for(int j=1; j<=n; j++)
                scanf("%d%d",&cost[j],&val[j]);
            if(type==0)
            {
                // 背包初始化要从0开始,而不是1
                for(int j=0; j<=t; j++) f[i][j]=-INF;
                // 将新判断的一组物品,开始时不同背包容量的价值都初始化为负数,保证至少选入这个物品。
                for(int j=1; j<=n; j++)
                    for(int k=t; k>=cost[j]; k--) // k要倒着枚举,保证不重复选取。
                    {

                        f[i][k]=max(f[i][k],f[i][k-cost[j]]+val[j]);
                        f[i][k]=max(f[i][k],f[i-1][k-cost[j]]+val[j]);
                        // 这两个写反了会错,为什么?
                    }
            }
            else if(type==1)
            {
                for(int k=0; k<=t; k++) f[i][k]=f[i-1][k];
                for(int j=1; j<=n; j++)
                    for(int k=cost[j]; k<=t; k++)// 这个k可正序也可反序枚举
                    {
                        f[i][k]=max(f[i][k],f[i-1][k-cost[j]]+val[j]);
                    }
            }
            else
            {
                //  标准1维数组优化的01背包问题,
                for(int k=0; k<=t; k++) f[i][k]=f[i-1][k];
                for(int j=1; j<=n; j++)
                    for(int k=t; k>=cost[j]; k--)
                    {
                        f[i][k]=max(f[i][k],f[i][k-cost[j]]+val[j]);
                    }
            }
        }
        int ans=max(f[m][t],-1);
        printf("%d
",ans);
    }
}
原文地址:https://www.cnblogs.com/dongdong25800/p/10789569.html