设$dp[i][j]$表示容量为$i$时的第$j$优解,因为是优解,肯定$dp[i][j]$是随着$j$增大不断递减的,这样的话对于一个新加进来的物品,它只可能从两个容量的转移的前$k$优解中转移过来,所以每次用两个指针扫一下转移过来就好了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=5005,K=52; 6 int vol[N],val[N],tmp[K],dp[N][K]; 7 int n,v,k,tot,p1,p2,ans; 8 int main () 9 { 10 scanf("%d%d%d",&k,&v,&n); 11 for(int i=1;i<=n;i++) 12 scanf("%d%d",&vol[i],&val[i]),tot+=vol[i]; 13 memset(dp,0xcf,sizeof dp),dp[0][1]=0; 14 for(int i=1;i<=n;i++) 15 for(int j=v;j>=vol[i];j--) 16 { 17 p1=p2=1; 18 for(int h=1;h<=k;h++) 19 { 20 int c=(dp[j-vol[i]][p1]+val[i]>dp[j][p2]); 21 tmp[h]=c?dp[j-vol[i]][p1++]+val[i]:dp[j][p2++]; 22 } 23 for(int h=1;h<=k;h++) dp[j][h]=tmp[h]; 24 } 25 for(int i=1;i<=k;i++) ans+=dp[v][i]; 26 printf("%d",ans); 27 return 0; 28 }