题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2639
题目大意:要求找出第k大的价值,相同的价值只能算一种,如17,14,14,13,,那么13为第3大。
解题思路:01背包的变种第k大01背包解决方法是从01背包的解法中改进而来。每次转移状态时,选择当前容量下的前k个价值,再找前面状态转移过来的前k个价值,然后合并,找出不相等的前k个价值,如果不多于k的话则用0补上,这样在总价值种数不足k的时候也可直接输出0.这样不断转移都可以保证找到前k大的价值(找不到也会是0)。本题复杂度为(O(NVK)),开始的时候我用了优先队列存放前k大的价值,很容易想,但速度不够快,后来改成合并两个有序序列的方法,时间从1564ms->109ms。
测试数据:
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
代码:
//合并有序序列 #include <stdio.h> #include <queue> #include <string.h> using namespace std; #define MAX 1100 #define max(a,b) (a)>(b)?(a):(b) int n,m,k; int dp[MAX][31],tpk; int ori[MAX],now[MAX]; int cost[MAX],val[MAX]; priority_queue<int> qu,quk;//默认的的优先级高 int main() { int i,j,s,t; scanf("%d",&t); while (t--) { scanf("%d%d%d",&n,&m,&k); for (i = 1; i <= n; ++i) scanf("%d",&val[i]); for (i = 1; i <= n; ++i) scanf("%d",&cost[i]); memset(dp,0,sizeof(dp)); for (i = 1; i <= n; ++i) for (j = m; j >= cost[i]; --j) { for (s = 1; s <= k; s++) { ori[s] = dp[j][s]; now[s] = dp[j-cost[i]][s] + val[i]; } ori[s] = now[s] = -1; int tpi = 1,tpj = 1,tpk = 1; while (tpk <= k && (ori[tpi] != -1 || now[tpj] != -1)) { if (ori[tpi] > now[tpj]) dp[j][tpk] = ori[tpi++]; else dp[j][tpk] = now[tpj++]; if (dp[j][tpk] != dp[j][tpk-1]) tpk++; } } printf("%d\n",dp[m][k]); } }
//优先队列 #include <stdio.h> #include <queue> #include <string.h> #include <algorithm> using namespace std; #define MAX 11000 #define max(a,b) (a)>(b)?(a):(b) int n,m,k; int dp[MAX][31],tpk; int cost[MAX],val[MAX]; priority_queue<int> qu,quk;//默认的的优先级高 int main() { int i,j,s,t; scanf("%d",&t); while (t--) { scanf("%d%d%d",&n,&m,&k); for (i = 1; i <= n; ++i) scanf("%d",&val[i]); for (i = 1; i <= n; ++i) scanf("%d",&cost[i]); memset(dp,0,sizeof(dp)); for (i = 1; i <= n; ++i) for (j = m; j >= cost[i]; --j) { //dp[j] = max(dp[j],dp[j-cost[i]]+val[i]) while (!qu.empty()) qu.pop(); for (s = 1; s <= k; s++) { qu.push(dp[j][s]); qu.push(dp[j-cost[i]][s] + val[i]); } s = 1,tpk = -1; while (1) { if (s > k || qu.empty()) break; if (qu.top() != tpk) dp[j][s++] = qu.top(),tpk = qu.top(); qu.pop(); } } printf("%d\n",dp[m][k]); } }