HDU-2639 Bone Collector II 01背包第K大值

题意:有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;    
}

 

 

你可能感兴趣的:(Collector)