题目链接:传送门
题目大意:有 n 组任务,m 个体力,每组任务有 k 个,分类为 f,每个任务花费 x 体力,得到 y 开心值,求最大开心值,若不能完成输出-1
分类为 0:这一组中的 k 个任务至少选择一个。
分类为 1:这一组中的 k 个任务最多选择一个。
分类为 2:这一组中的 k 个任务随便选择。
分析:
1.对于分类 0,若当前判断到一个任务 x,则有两种情况:
(1)它是该组第一个被选择的任务,则它更新的状态只能是将上一层的状态转移更新到当前位置。
(2)它不是第一个被选择的任务,则它可以由当前组的状态转移更新到当前位置。
为了方便判断处理第一个任务,初始化当前层为 -inf
2.对于分类 1,因为只能选一个或者不选,则它只能由上一层状态转移更新。
3.对于分类 2,就是普通的 01背包问题
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> #include <stack> #include <cctype> #include <queue> #include <string> #include <vector> #include <set> #include <map> #include <climits> #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define fi first #define se second #define ping(x,y) ((x-y)*(x-y)) #define mst(x,y) memset(x,y,sizeof(x)) #define mcp(x,y) memcpy(x,y,sizeof(y)) using namespace std; #define gamma 0.5772156649015328606065120 #define MOD 1000000007 #define inf 0x3f3f3f3f #define N 1505 #define maxn 500005 typedef pair<int,int> PII; typedef long long LL; int dp[250][250]; int w[250],v[250]; int n,m,k,vv; int main(){ int i,j,group,id; while(scanf("%d%d",&n,&m)!=EOF){ mst(dp,0); for(i=1;i<=n;++i){ scanf("%d%d",&k,&vv); for(j=1;j<=k;++j) scanf("%d%d",&w[j],&v[j]); if(vv==0){ for(int l=0;l<=m;++l)dp[i][l]=INT_MIN+10000000; for(int l=1;l<=k;++l) for(int h=m;h>=w[l];--h){ dp[i][h]=max(dp[i][h],max(dp[i-1][h-w[l]],dp[i][h-w[l]])+v[l]); } } else if(vv==1){ for(int l=0;l<=m;++l)dp[i][l]=dp[i-1][l]; for(int l=1;l<=k;++l) for(int h=m;h>=w[l];--h) dp[i][h]=max(dp[i][h],dp[i-1][h-w[l]]+v[l]); } else{ for(int l=0;l<=m;++l)dp[i][l]=dp[i-1][l]; for(int l=1;l<=k;++l) for(int h=m;h>=w[l];--h){ dp[i][h]=max(dp[i][h],dp[i][h-w[l]]+v[l]); } } } int temp=max(dp[n][m],-1); printf("%d ",temp); } return 0; }