题目描述
求01背包前k优解的价值和
输入输出格式
输入格式:
第一行三个数K、V、N
接下来每行两个数,表示体积和价值
输出格式:
前k优解的价值和
输入输出样例
输入样例#1:
2 10 5
3 12
7 20
2 4
5 6
1 1
输出样例#1:
57
说明
对于100%的数据,K≤50,V≤5000,N≤200
思路:
这道题本身不算特别难,设置一个二维数组dp[i][j]
代表背包容量为i的时候第j优解的价值。V的范围是5000,N的范围是200,如果按照01背包求最优解的话时间复杂度为1e6
可是由于是求第k优,k的范围为1~50,因此我们得在1e6的循环中,用O(k)的复杂度求出前k优,这时候,我们就需要用到归并排序取前50大
这道题太毒瘤了,条件里也没交代说必须正好装满V。。。结果最后答案必须是正好装满V的答案。。。
答案见代码:
代码:
/*************************************************************************
> File Name: p.cpp
> Author: Zcy
> Mail: 296763002@qq.com
> Created Time: 三 1/23 18:16:17 2019
************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <algorithm>
using namespace std;
int dp[5005][55] = {0};
int main () {
int K, V, N, v, w;
scanf("%d%d%d", &K, &V, &N);
dp[0][0] = 1; //正好装满初始化dp[0][0] = 1, 若是类似01背包可以不必装满的话,就是初始化dp[i][0] = 1 (0 <= i <= V)
for (int i = 1; i <= N; i++) {
scanf("%d%d", &v, &w);
for (int j = V; j >= v; j--) {
int p1 = 1, p2 = 1;
int c[55] = {0};
while(p1 <= dp[j][0] || p2 <= dp[j - v][0]) {
if (p2 > dp[j - v][0] || (p2 <= dp[j - v][0] && p1 <= dp[j][0] && dp[j][p1] >= dp[j - v][p2] + w)) {
c[++c[0]] = dp[j][p1];
p1++;
} else {
c[++c[0]] = dp[j - v][p2] + w;
p2++;
}
if (c[0] >= K) break;
}
for (int ppp = 0; ppp <= c[0]; ppp++) {
dp[j][ppp] = c[ppp];
}
}
}
int ans = 0;
for (int i = 1; i <= K; i++)
ans += dp[V][i];
printf("%d\n", ans);
return 0;
}
如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢