这题和典型的01背包求最优解不同,是要求第k优解,所以,最直观的想法就是在01背包的基础上再增加一维表示第k大时的价值。
具体思路见下面的参考链接,说的很详细
参考连接:
http://laiba2004.blog.163.com/blog/static/8835120220138611342496/
http://hi.baidu.com/chenyun00/item/1c6c44318acc8bfaa88428c7
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=101; const int maxv=1001; const int maxk=31; int n,v,k; int dp[maxv][maxk]; //dp[j][k]表示容量为j时,第k大的值 int w[maxn]; //价值 int vv[maxn]; //容量 //一开始tmp只开了maxk个大小,导致WA。。。因为对应的每个k,有dp[j][z]和dp[j-vv[i]][z]+w[i]两个状态,所以要开2*maxk大小 //int tmp[maxk*2]; int tmp1[maxk*2]; int tmp2[maxk*2]; int main() { int t,idx,cnt; scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&v,&k); for(int i=1;i<=n;i++) scanf("%d",&w[i]); //价值 for(int i=1;i<=n;i++) scanf("%d",&vv[i]); //容量 memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++){ for(int j=v;j>=vv[i];j--){ //idx=0; for(int z=1;z<=k;z++){ tmp1[z]=dp[j][z]; tmp2[z]=dp[j-vv[i]][z]+w[i]; } /* sort(tmp+1,tmp+idx+1); cnt=1; dp[j][1]=tmp[idx]; for(int q=idx-1;q>=1&&cnt<k;q--){ if(tmp[q]!=tmp[q+1]) dp[j][++cnt]=tmp[q]; } while(cnt<k){ dp[j][++cnt]=0; } */ //其实不需要按照上面用排序,可以用开两个数组tmp1和tmp2存储,这两个数组都是有序序列 //这样的话,从原本的931ms减少到125ms tmp1[k+1]=-1;tmp2[k+1]=-1; //将tmp1和tmp2的第k+1个元素设为-1,即设成较小的值 int a=1,b=1; cnt=0; while(cnt<k && (a!=k+1||b!=k+1)){ if(tmp1[a]>tmp2[b]){ dp[j][++cnt]=tmp1[a]; a++; } else{ dp[j][++cnt]=tmp2[b]; b++; } if(dp[j][cnt]==dp[j][cnt-1]) cnt--; } } } printf("%d ",dp[v][k]); } return 0; }