把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; }