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);
}
}