hdu 2639 (第k小的01背包)
题意:第k小的01背包,重复的选项算一个
分析:01背包问题,只考虑到第i个问题的各个体积的最优解,而第k大的01背包则需要更多的选项,有个博客举了这样一个例子
我们年纪一共10个班,如果我想知道年纪第一,我需要知道每个班级的第一名,一比较,那么我就知道年纪第一是谁了
如果我要知道年纪前十名,那么,我只要知道每个班的前10名,那么我比较之后就知道了年级的前十名
dp[i][j]表示体积为i时,价值为第j大的价值,每次选择物品的时候,计算出所有的体积,把前k名按照顺序插入到dp[i]中,这样,最后得到答案dp[n][v]
#include<bits/stdc++.h> using namespace std; const int maxn=1e3+5; int dp[maxn][35],v[105],w[105],A[35],B[35]; int main(){ int n,V,t,k; scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&V,&k); for(int i=1;i<=n;i++) scanf("%d",v+i); for(int i=1;i<=n;i++) scanf("%d",w+i); memset(dp,0,sizeof(dp)); int a,b,c,kk; for(int i=1;i<=n;i++) for(int j=V;j>=w[i];j--){ for(kk=1;kk<=k;kk++){ A[kk]=dp[j][kk]; B[kk]=dp[j-w[i]][kk]+v[i]; } A[kk]=B[kk]=-1; a=b=c=1; while(c<=k&&(A[a]!=-1||B[b]!=-1)){ if(A[a]>B[b]) dp[j][c]=A[a++]; else dp[j][c]=B[b++]; if(dp[j][c]!=dp[j][c-1]) c++; } } printf("%d\n",dp[V][k]); } return 0; }