您的位置:首页 > 其它

vijos P1412多人背包 DP的前k优解

2017-02-14 15:41 197 查看
https://vijos.org/p/1412

把dp设成,dp[i][v][k]表示在前i项中,拥有v这个背包,的第k大解是什么。

那么dp[i][v][1...k]就是在dp[i - 1][v][1...k]和dp[i - 1][v - w[i]][1...k] + val[i]中合并得来。

用O(k)的算法可以找出来,因为是有序的。

注意同一个物品只能用一次。

dp的初始化就有些不同。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 5000 + 20;
int w[maxn], val[maxn];
int dp[maxn][50 + 20];
int k, tot, n;
int a[maxn], b[maxn];
vector<int>vc;
void work() {
scanf("%d%d%d", &k, &tot, &n);
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &w[i], &val[i]);
}
memset(dp, -0x3f, sizeof dp);
dp[0][1] = 0;
for (int i = 1; i <= n; ++i) {
for (int v = tot; v >= w[i]; --v) {
int lena = 0, lenb = 0;
for (int h = 1; h <= k; ++h) {
a[++lena] = dp[v][h];
b[++lenb] = dp[v - w[i]][h] + val[i];
}
int toa = 1, tob = 1;
for (int h = 1; h <= k; ++h) {
if (a[toa] > b[tob] && toa <= lena) {
dp[v][h] = a[toa++];
} else {
dp[v][h] = b[tob++];
}
}
}
}
//    cout << dp[tot][1] << endl;
//    cout << dp[tot][2] << endl;
int ans = 0;
for (int i = 1; i <= k; ++i) {
ans += dp[tot][i];
}
ans = max(ans, 0);
cout << ans << endl;
}

int main() {
#ifdef local
freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
work();
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: