HDU 3535 AreYouBusy
题解:dp[i][j]表示的是在第i组剩余时间为j时的快乐值,我们需要对每一组工作进行一次DP。
第一类:即s==0时,表示该组中工作必须要选且至少选一项。为了保证不出现不选的现象,我们应该把DP数组初始化为负无穷。状态转移方程为: dp[i][k]=max(dp[i][k],max(dp[i-1][k-c[j]]+val[j],dp[i][k-c[j]]+val[j])); dp[i][k]表示不选该组中的第j个工作,dp[i-1][k-c[j]]+val[j]表示选第j项工作且是第一次在本组中选。dp[i][k-c[j]]+val[j])表示选第j项工作且不是第一次在本组中选。
第二类:即s==1时,最多选一项,即要么不选,一旦选,只能是第一次选。状态转移方程为: dp[i][k]=max(dp[i][k],dp[i-1][k-c[j]]+val[j]) 由于要保证得到全局最优解,所以在该组DP开始以前,应该将上一组的DP结果先复制到这一组的dp[i]数组里,因为这一组的数据是在上一组数据的基础上进行更新的。
第三类:即s==2时,任意选,即不论选不选,选几次都可以。状态转移方程与第一类一致,不同的在于第三类对dp的初始化为上一组的值,而不是初始化为负无穷。
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #define inf -0x3f3f3f3f
6 using namespace std;
7 const int maxn=110;
8
9 int n,t;
10 int dp[maxn][maxn];
11 int m,s,c[maxn],val[maxn];
12 int main()
13 {
14 while(~scanf("%d%d",&n,&t))
15 {
16 memset(dp,0,sizeof(dp));
17 for(int i=1;i<=n;i++)
18 {
19 scanf("%d%d",&m,&s);
20 for(int j=1;j<=m;j++)
21 scanf("%d%d",&c[j],&val[j]);
22 if(s==0)
23 {
24 for(int j=0;j<=t;j++)
25 dp[i][j]=inf;
26 for(int j=1;j<=m;j++)
27 {
28 for(int k=t;k>=c[j];k--)
29 {
30 dp[i][k]=max(dp[i][k],max(dp[i-1][k-c[j]]+val[j],dp[i][k-c[j]]+val[j]));
31 }
32 }
33 }
34 else if(s==1)
35 {
36 for(int j=0;j<=t;j++)
37 {
38 dp[i][j]=dp[i-1][j];
39 }
40 for(int j=1;j<=m;j++)
41 {
42 for(int k=t;k>=c[j];k--)
43 {
44 dp[i][k]=max(dp[i][k],dp[i-1][k-c[j]]+val[j]);
45 }
46 }
47 }
48 else if(s==2)
49 {
50 for(int j=0;j<=t;j++)
51 {
52 dp[i][j]=dp[i-1][j];
53 }
54 for(int j=1;j<=m;j++)
55 {
56 for(int k=t;k>=c[j];k--)
57 {
58 dp[i][k]=max(dp[i][k],max(dp[i-1][k-c[j]]+val[j],dp[i][k-c[j]]+val[j]));
59 }
60 }
61 }
62
63 }
64 dp[n][t]=max(dp[n][t],-1);
65 printf("%d\n",dp[n][t]);
66 }
67 return 0;
68 }