不得不说,我这个菜鸡做这题真的是一脸懵,自己也没想明白,看别人的看明白了,但是有的部分我还是不明白,先说一下这道题为什么要开二维数组,我个人认为是这样的
为什么要开二维数组:
S == 0(类型0)时,如果你想从这些物品中只取一个,那么转移方程是这样的 :
dp[i][s] = max(dp[i][s],dp[i-1][s-cost[k]]+val[k]);
因为我们开始时候把dp[i][j](j 由 0-T)设置为负无穷,所以如果有这个方程至少可以保证一定会取一个,我想上面的方程是让每个地方都不再是-INF,但是我们可能还会放多个,那么就用下面的方程
dp[i][s] = max(dp[i][s],dp[i][s-cost[k]]+val[k]);
把俩和在一起:
dp[i][s] = max(dp[i][s],dp[i][s-cost[k]]+val[k]);
dp[i][s] = max(dp[i][s],dp[i-1][s-cost[k]]+val[k]);
S == 1时你就差不多明白为啥开二维了,把每一个dp[i][j]都初始化为dp[i-1][j],都初始化为一个不拿,再让每一个dp[i][j]比较拿一个和不拿谁大谁小,因为就拿一个,所以用下面的方程(上面也提到过,必须是i-1)
dp[i][s] = max(dp[i][s],dp[i-1][s-cost[k]]+val[k]);
S == 2时,也是一个道理,这次是随便取,把每一个dp[i][j]都初始化为dp[i-1][j],都初始化为一个不拿,但这次转移方程是:
dp[i][s] = max(dp[i][s],dp[i][s-cost[k]]+val[k]);
最后ac代码是
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 100+8;
int dp[maxn][maxn];
int M,S,C,G,N,T;
int cost[maxn],val[maxn];
int main()
{
while(scanf("%d%d",&N,&T) == 2)//N组任务,T时间
{
memset(dp,0,sizeof(dp));
int index = 0;
for(int i = 1; i <= N; i++)
{
scanf("%d%d",&M,&S); //M是任务量,S是类型
for(int k = 1; k <= M; k++)
{
scanf("%d%d",&cost[k],&val[k]);
}
if(S == 0)
{
for(int j = 0; j <= T; j++) dp[i][j] = -INF;
for(int k = 1; k <= M; k++)
{
for(int s = T; s >= cost[k]; s--)
{
dp[i][s] = max(dp[i][s],dp[i][s-cost[k]]+val[k]);
dp[i][s] = max(dp[i][s],dp[i-1][s-cost[k]]+val[k]);
//我也不知道这里是为什么不能交换他俩的顺序,
//下面有一个别人的解释,
//如果有大佬看明白了请告诉我一声,好人一生平安
}
}
}
else if(S == 1)
{
for(int j = 0; j <= T; j++) dp[i][j] = dp[i-1][j];
for(int k = 1; k <= M; k++)
{
for(int s = T; s >= cost[k]; s--)
{
dp[i][s] = max(dp[i][s],dp[i-1][s-cost[k]]+val[k]);
}
}
}
else if(S == 2)
{
for(int j = 0; j <= T; j++) dp[i][j] = dp[i-1][j];
for(int k = 1; k <= M; k++)
{
for(int s = T; s >= cost[k]; s--)
{
dp[i][s] = max(dp[i][s],dp[i][s-cost[k]]+val[k]);
}
}
}
}
int ans = max(dp[N][T],-1);
printf("%d\n",ans);
}
return 0;
}
别人的解释:
感谢大佬看完,奥利给