点击打开链接
3 5 10 2 1 2 3 4 5 5 4 3 2 1 5 10 12 1 2 3 4 5 5 4 3 2 1 5 10 16 1 2 3 4 5 5 4 3 2 1
12 2 0
普通01背包的状态转移方程为:dp[i][j]=max(dp[i-1][j],dp[i-1][j-v]+w)。由于状态转移的过程中已经枚举了所有策略,所以假设我们已经知道前面的状态的前K优解,那么当前状态的前k优解也可以求得。我们用dp[i][j][k]表示前i个物品,花费为j的第K优解,我们把dp[i][j]看成前i个物品花费为j的解的序列,那么dp[i][j]序列就是由dp[i-1][j]序列与dp[i-1][j-v]+w序列合并而成的新序列,由于我们要求K优解,所以我们只需要保留新序列的前K优值就行了。
背包九讲上说:对于求次优解、第K优解类的问题,如果相应的最优解问题能写出状态转移方程、用动态规划解决,那么求次优解往往可以相同的复杂度解决,第K优解则比求最优解的复杂度上多一个系数K。其基本思想是将每个状态都表示成有序队列,将状态转移方程中的max/min转化成有序队列的合并。
具体细节见代码:
#include<stdio.h> #include<iostream> #include<string> #include<string.h> #include<vector> #include<algorithm> #include<queue> #include<stack> #define nn 1100 #define inff 0x3fffffff #define mod 1000000007 using namespace std; typedef long long LL; int n,v,k; int val[nn],w[nn]; int dp[110][1100][35]; int f[nn]; int main() { int t,i,j,g; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&v,&k); for(i=1;i<=n;i++) scanf("%d",&val[i]); for(i=1;i<=n;i++) scanf("%d",&w[i]); for(i=0;i<=n;i++) { for(j=0;j<=v;j++) { for(g=1;g<=k+1;g++) dp[i][j][g]=-inff; } } for(i=0;i<=v;i++) dp[0][i][1]=0; int ix1,ix2; for(i=1;i<=n;i++) { for(j=v;j>=0;j--) { for(g=1;g<=k;g++) { dp[i][j][g]=dp[i-1][j][g]; f[g]=dp[i][j][g]; } ix1=ix2=1; if(j-w[i]<0) continue; for(g=1;g<=k;g++) { if(f[ix1]>dp[i-1][j-w[i]][ix2]+val[i]) { dp[i][j][g]=f[ix1]; ix1++; } else if(f[ix1]<dp[i-1][j-w[i]][ix2]+val[i]) { dp[i][j][g]=dp[i-1][j-w[i]][ix2]+val[i]; ix2++; } else { dp[i][j][g]=f[ix1]; ix1++; ix2++; } } } } printf("%d\n",max(0,dp[n][v][k])); } return 0; }
#include<stdio.h> #include<iostream> #include<string> #include<string.h> #include<vector> #include<algorithm> #include<queue> #include<stack> #define nn 1100 #define inff 0x3fffffff #define mod 1000000007 using namespace std; typedef long long LL; int n,v,k; int val[nn],w[nn]; int dp[1100][35]; int f[nn]; int main() { int t,i,j,g; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&v,&k); for(i=1;i<=n;i++) scanf("%d",&val[i]); for(i=1;i<=n;i++) scanf("%d",&w[i]); for(i=0;i<=n;i++) { for(j=0;j<=v;j++) { for(g=1;g<=k+1;g++) dp[j][g]=-inff; } } for(i=0;i<=v;i++) dp[i][1]=0; int ix1,ix2; for(i=1;i<=n;i++) { for(j=v;j>=0;j--) { for(g=1;g<=k;g++) { f[g]=dp[j][g]; } ix1=ix2=1; if(j-w[i]<0) continue; for(g=1;g<=k;g++) { if(f[ix1]>dp[j-w[i]][ix2]+val[i]) { dp[j][g]=f[ix1]; ix1++; } else if(f[ix1]<dp[j-w[i]][ix2]+val[i]) { dp[j][g]=dp[j-w[i]][ix2]+val[i]; ix2++; } else { dp[j][g]=f[ix1]; ix1++; ix2++; } } } } printf("%d\n",max(0,dp[v][k])); } return 0; }