HDU 2639 Bone Collector II (dp)

题目链接

Problem Description

The title of this problem is familiar,isn't it?yeah,if you had took part in the "Rookie Cup" competition,you must have seem this title.If you haven't seen it before,it doesn't matter,I will give you a link:

Here is the link:http://acm.hdu.edu.cn/showproblem.php?pid=2602

Today we are not desiring the maximum value of bones,but the K-th maximum value of the bones.NOTICE that,we considerate two ways that get the same value of bones are the same.That means,it will be a strictly decreasing sequence from the 1st maximum , 2nd maximum .. to the K-th maximum.

If the total number of different values is less than K,just ouput 0.

Input

The first line contain a integer T , the number of cases.

Followed by T cases , each case three lines , the first line contain two integer N , V, K(N <= 100 , V <= 1000 , K <= 30)representing the number of bones and the volume of his bag and the K we need. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.

Output

One integer per line representing the K-th maximum of the total value (this number will be less than 231).

Sample Input

3
5 10 2
1 2 3 4 5
5 4 3 2 1
5 10 12
1 2 3 4 5
5 4 3 2 1
5 10 16
1 2 3 4 5
5 4 3 2 1

Sample Output

12
2
0

分析:

简单解释一下题目要求。输入给你n中物品,背包的容量(maxvolum)和一个整数k

求在maxvolum的限制条件下所能得到的第k大的价值

这是一个很典型的第k优解的问题

首先看普通01背包的状态转移方程 : fi = max( fi-1,fi] + val[i])。

如果要求第k优解,那么应该设定另一个状态转移方程: fi[k]表示在j背包容量限制下,前i个物品所能获得的第k大价值。

然后原方程就可以解释为:fi这个有序列是由fi-1和fi-1]+val[i]这两个有序队列合并(合并的方式是通过max求取两个钟的较大的值)得到的。

有序列fi-1即fi-1[1..K],fi-1]+val[i]则理解为在fi-1][1..K]的每个数上加上val[i]后得到的有序列。

那么fi[k]就是上述两个有序列(也是通过max求两个较大的那个)合并得到

转换到代码当中去,我们需要找两个数组chose[i] 和 not_chose[i]来存储两个序列(每一个序列其实是由一系列的状态构成的)

最后将这两个数组合并即有了第k(k from 1 to k)优解的序列.

代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<set>
using namespace std;
bool cmp(int a,int b)
{
    return a>b;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int N,V,K,w[1003],v[1003],dp[1003][33]= {0},c[1003];
        scanf("%d%d%d",&N,&V,&K);
        for(int i=0; i<N; i++)

            scanf("%d",&w[i]);
        for(int i=0; i<N; i++)
            scanf("%d",&v[i]);
        for(int i=0; i<N; i++)
            for(int j=V; j>=v[i]; j--)
            {
                int k1=0;
                for(int t=0; t<K; t++)
                {
                    c[k1++]=dp[j][t];
                    c[k1++]=dp[j-v[i]][t]+w[i];
                }
                sort(c,c+K*2,cmp);
                k1=1;
                dp[j][0]=c[0];
                for(int t=1; t<K*2&&k1<K; t++)
                    if(c[t]!=c[t-1])
                        dp[j][k1++]=c[t];
            }
        printf("%d
",dp[V][K-1]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cmmdc/p/6766877.html