题意:有N件物品和V体积的背包,没见物品由所占空间和价值组成,现问第K大能够装多少物品?
解法:通过增加一维信息f[i][j][k]表示占用放到第i件物品时空间为j是第k大值时多少,f[i][j][k]无法给出一个明确的转移的方程,但是我们知道第i件物品若放置的话那么能够由f[i][j-w[i]][1...K]生成K中状态,如果不放置的话就能由f[i][j][0...K]生成K种状态,分别由这2*K个状态能够得到放或者是不放的前K大,因为综合的前K大一定在放的前K大或者是不放的前K大里面。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; int N, V, K; int w[105], p[105], f[1005][35]; int c1[35], c2[35]; int solve() { memset(f, 0, sizeof (f)); for (int i = 1; i <= N; ++i) { for (int j = V; j >= w[i]; --j) { for (int h = 1; h <= K; ++h) { c1[h] = f[j-w[i]][h] + p[i]; c2[h] = f[j][h]; } int x = 1, y = 1, h = 1; c1[K+1] = c2[K+1] = 0; while (h <= K && (x <= K || y <= K)) { if (c1[x] > c2[y]) { if (c1[x] != f[j][h-1]) f[j][h++] = c1[x]; ++x; } else { if (c2[y] != f[j][h-1]) f[j][h++] = c2[y]; ++y; } } } } return f[V][K]; } int main() { int T; scanf("%d", &T); while (T--) { scanf("%d %d %d", &N, &V, &K); for (int i = 1; i <= N; ++i) { scanf("%d", &p[i]); } for (int i = 1; i <= N; ++i) { scanf("%d", &w[i]); } printf("%d\n", solve()); } return 0; }