第K大01背包

其实这个问题,真的挺好想的,但是我咋想了那么久呢~~

很好理解,第K大01背包一定基于01背包,dp数组也很容易的想到由dp[V]  ---->   dp[V][K],来表示背包容量是V时候的第K大背包

然后就是状态转移方程了,多写一写,你也能手推出来的,不能被吓到

dp[V][1] = max_第一大(dp[v][1],dp[v-w][1]+vi)

dp[V][2] = max_第二大数(dp[v][1],dp[v-w][1]+vi,dp[v][2],dp[v-w][2]+vi) =  max_第二大数(dp[v][1],dp[v][2],dp[v-w][2]+vi)

从而得到一般式子

dp[v][k] = max_第K大(dp[v][1],dp[v][2],....dp[v][k],dp[v-w][1]+vi,.....dp[v-w][k]+vi

明白了这两个,代码方面就比较好实现了

可以用排序来进行

但是一看排列,发现取第K大值分为两部分,且排列都是降序,所以我们可以用两个数组存储起来,然后进行赋值(复杂度也比较低)

/*
dp[x][y]表示的是容量为x的第k大值
所以dp[x][1] = max_(第一大值){dp[x][1],dp[x-v][1]+w}
dp[x][2] = max_(第二大值){dp[x][1],dp[x][2],dp[x-v][1]+w,dp[x-v][2]+w}
依次类推~~
*/
/*
 因为dp[j][1]...dp[j][k]与dp[j-w[i]][1]+v[i]...dp[j-w[i]][k]+v[i]
 是依次递减的,那么我们可以用两个数组将这两组数组保存起来,
 再O(N)的时间内求得第K大。
 */
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1005;
int dp[maxn][maxn];
int n,W,K;//W:总容量值,K第K大值
int v[maxn],w[maxn];//价值,一个为体积
int s1[maxn],s2[maxn];
void KthZeroOnePack()
{
    for(int i = 0;i < n;i++)//遍历了每一个物品
    {
        for(int j = W;j >= w[i];j--)//层铺每一层体积
        {
            for(int th = 1;th <= K;th++)//求取前k大值
            {
                //0 - k-1   到K结束
                s1[th-1] = dp[j][th];//遍历存储每一个可能取到的值,且s1是递减的
                s2[th-1] = dp[j - w[i]][th] + v[i];//遍历存储每一个可能取到的值,且s2是递减的
            }
            //特判结束点
            s1[K] = s2[K] = -1;
            int cnt = 1,cnt1 = 0,cnt2 = 0;
            //从第一大开始
            while(cnt <= K && (s1[cnt1] != -1 || s2[cnt2] != -1))
            {
                if(s1[cnt1] > s2[cnt2])dp[j][cnt] = s1[cnt1++];
                else dp[j][cnt] = s2[cnt2++];
                //严格递减
                if(dp[j][cnt] != dp[j][cnt-1]) cnt++;
            }

        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&W,&K);
        memset(dp,0,sizeof(dp));
        for(int i = 0;i < n;i++)
        {
            scanf("%d",&v[i]);
        }
        for(int i = 0;i < n;i++)
        {
            scanf("%d",&w[i]);
        }
        KthZeroOnePack();
        printf("%d\n",dp[W][K]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/DF-yimeng/p/9334875.html

时间: 2024-08-01 10:04:20

第K大01背包的相关文章

HDU2639 第k小01背包 xingxing在努力

这个题目是求解第k小01背包, 我们只需要再多加一维表示容量为j时的价值即可..代码里面用了归并排序的思想来求解f[j][k], 代码如下: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int f[1000+10][35]; int A[35], B[35]; //A选 B不选 int W[100+10], V[100+10]; int N, v, K; v

[HDOJ2639]Bone Collector II(第k优01背包)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2639 题意:求01背包的第k优解 dp(i, j)表示容量为j时的i优解 对于第二维的操作和01背包几乎一样,只是我们只需要关注每一次取的前k大个即可. 1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstring> 5 #include <cli

hdu1864 最大报销额(01背包)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1864 Problem Description 现有一笔经费能够报销一定额度的发票.同意报销的发票类型包含买图书(A类).文具(B类).差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价值不得超过600元.现请你编敲代码,在给出的一堆发票中找出能够报销的.不超过给定额度的最大报销额. Input

HDU - 2639(01背包求第K大值)

传送门 题意: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. 输入:T组数据 体积V 要求的K    N , V, K(N <= 100 , V <= 1000 , K <= 30) 各项价值 各项

HDU2639(01背包第K大)

Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3437    Accepted Submission(s): 1773 Problem Description The title of this problem is familiar,isn't it?yeah,if you had took par

HDU 2639 01背包求第k大

Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3718    Accepted Submission(s): 1903 Problem Description The title of this problem is familiar,isn't it?yeah,if you had took par

HDU 2639 Bone Collector II(01背包变形【第K大最优解】)

Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4739    Accepted Submission(s): 2470 Problem Description The title of this problem is familiar,isn't it?yeah,if you had took pa

hdu 2639 Bone Collector II(01背包 第K大价值)

Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3355    Accepted Submission(s): 1726 Problem Description The title of this problem is familiar,isn't it?yeah,if you had took par

01背包变种 第k解问题 hdu 2639

先说说普通01包的状态问题吧 普通的01背包,在状态转移的过程中为了求出最优解,一定是遍历了所有的情况 然后再求的最优解.那么对于第k最优解问题,我们只需要再加一个维度,用来记录每一个状态k优解的状态就好了. 在普通背包过程中 每次的选举的状态为dp[i-1][j],dp[i-1][j-c[i]+w[i]  为了求解最优情况 我们一般是对这两个状态取最大值 然后依次遍历 得到最大值.那么,为了得到第k大的解,我们就需要另外使用数组来对两种状态的所有值记录下来 然后选取第k大的情况 上代码 #in