2639骨头问题2(01背包的第k大值)

来源:互联网 发布:linux系统运维 编辑:程序博客网 时间:2024/05/01 17:42
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).
 
对01背包理解还是不透彻,看了大神的代码都半天没反应过来。
大神给dp数组加了一个维度,存放最大的k个值。
只有一个物品时候,只有放和不放两个值,存到k数组。这是背包的两个可能的状态,并排序
当有两个物品时候,在第一个放和不放状态上又可以有放和不放。以此类推。所以有了k的循环,每次都把放和不放的状态与原来的几种状态依次相加,得到新的状态
因为dp数组初始化都是0,是有序的,每次放完a,b中间数组都是严格递减的,原因是dp[j][k]一定大于dp[j][k+1],所以无论取dp[j][k]或者dp[j][k-vol[i]]+val[i]都是严格递减
所以排序时候可以用类似归并排序的合并方法。大神把排序的数组最后一个设为负数,就不用管边界问题,非常好的方法。
每次找出前k个最优值,然后存入dp数组。如果不满k个,则后面的是0,对下一次决策没影响,到时候对结果也没影响,因为结果让不满k个输出0,只是排序的时候注意一下去重。上大神代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


#define MAXN 105
#define MAXV 1005


int MyMax(int a,int b)
{
    return (a>b?a:b);
}


int main()
{
    int t,n,v,m;
    while(scanf("%d",&t)!=EOF)
    {
        while(t--)
        {
            int i,j,k;
            int val[6],vol[6],dp[11][3];
            int a[35],b[35];
            scanf("%d%d%d",&n,&v,&m);
            for(i=1;i<=n;i++)
            {
                scanf("%d",&val[i]);
            }
            for(i=1;i<=n;i++)
            {
                scanf("%d",&vol[i]);
            }
            memset(dp,0,sizeof(dp));
            for(i=1;i<=n;i++)
            {
                for(j=v;j>=vol[i];j--)
                {
                    for(k=1;k<=m;k++)
                    {
                        a[k]=dp[j-vol[i]][k]+val[i];
                        b[k]=dp[j][k];
                    }
                    int x,y,z;
                    x=y=z=1;
                    a[k]=b[k]=-1;
                    while(z<=m&&(y<=m||x<=m))
                    {
                        if(a[x]>b[y])
                        {
                            dp[j][z]=a[x++];
                        }
                        else
                        {
                            dp[j][z]=b[y++];
                        }
                        if(dp[j][z]!=dp[j][z-1])
                        {
                            z++;
                        }
                    }
                }
            }
            printf("%d\n",dp[v][m]);
        }
    }
    return (0);
}
0 0