这道题是一个二维的背包问题,和0-1背包问题极其类似,只不过多了一个维度而已。
第一遍做的时候错误,是因为没有分清楚数组每一维的含义。在这里,dp(i,j,g)的i表示取到第i个物品的时候,j表示到达时刻j的时候,g表示取得的物品的数目。最开始把j有时候当做小于等于时刻j的时候,有时候当做正好时刻k的时候,导致了开始的错误。
改正了这个错误以后,提交还是一直不对。发现在ans比较的时候出问题了,ans如果赋初值为-1,那么当无法到达的时候,ans不会变成0.
学长帮我改了一遍代码,我写的时候记录物品的数组(即times跟value)是从0开始赋值的,学长从1开始赋值。从0开始赋值的一个缺点就是在dp中,i等于0的时候要手动赋值。
代码如下(没有进行空间优化):
#include<iostream>
#include<cstring>
using namespace std;
int times[105];
int value[105];
int dp[105][1005][105];
int main(){
freopen("data.txt","r",stdin);
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--){
int n,m,l;
cin>>n>>m>>l;
for(int i=1;i<=n;++i){
cin>>times[i]>>value[i];
}
memset(dp,-1,sizeof(dp));
/*for(int t=l;t>=0;--t){
if(t==times[1])
dp[1][t][1]=value[1];//
}*/
for(int i=0;i<=n;++i){
//for(int t=0;t<=l;++t){
dp[i][0][0]=0;
//}
}
for(int i=1;i<=n;++i){
for(int t=0;t<=l;t++)
for(int g=0;g<=min(i,m);g++)
dp[i][t][g]=dp[i-1][t][g];
for(int t=times[i];t<=l;t++){
//if(t-times[i]<0)break;
for(int g=0;g<=min(i,m);g++){
if(g==0||dp[i-1][t-times[i]][g-1]==-1)continue;
dp[i][t][g]=max(dp[i-1][t-times[i]][g-1]+value[i],dp[i][t][g]);
//cout<<dp[i][t][g]<<endl;
}
}
}
int ans=0;
for(int i=0;i<=l;++i){
//cout<<dp[n][i][m]<<endl;
if(dp[n][i][m]>ans)ans=dp[n][i][m];
}
cout<<ans<<endl;
}
return 0;
}
进行空间优化以后的代码:
#include<iostream>
#include<cstring>
using namespace std;
int times[105];
int value[105];
int dp[1005][105];
int main(){
// freopen("data.txt","r",stdin);
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--){
int n,m,l;
cin>>n>>m>>l;
for(int i=1;i<=n;++i){
cin>>times[i]>>value[i];
}
memset(dp,-1,sizeof(dp));
/*for(int t=l;t>=0;--t){
if(t==times[1])
dp[1][t][1]=value[1];//
}*/
dp[0][0]=0;
//}
for(int i=1;i<=n;++i){
for(int t=l;t>=times[i];t--){
//if(t-times[i]<0)break;
for(int g=min(i,m);g>=0;g--){
if(g==0||dp[t-times[i]][g-1]==-1)continue;
dp[t][g]=max(dp[t-times[i]][g-1]+value[i],dp[t][g]);
//cout<<dp[i][t][g]<<endl;
}
}
}
int ans=0;
for(int i=0;i<=l;++i){
//cout<<dp[n][i][m]<<endl;
if(dp[i][m]>ans)ans=dp[i][m];
}
cout<<ans<<endl;
}
return 0;
}