rqnoj-123-多人背包-第K最优解(好题)

这道题目是在01背包的基础上求出前K个最优解。

dp[i][j]: 背包容量为i,第j优解的值。

由于任意两个背包不能完全相同,所以只初始化dp[0][1]=0;

因为要求必须恰好装满,所以其他的初始化为最小。

dp[i][1....k]=max(dp[i][1..k],dp[i-w][1...k]+v);

即dp[i][1....k]中的k个元素为dp[i][1..k]中的k个元素+dp[i-w][1...k]中的k个元素的前k大的元素。

合并两个数组的时候利用归并排序的原理合并。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int dp[5050][55];
int num[201];
void add(int x,int k,int w,int v)
{
    int i;
    int t1,t2;
    t1=t2=1;
    for(i=1;i<=k;i++)
    {
        if(dp[x][t1]>dp[x-w][t2]+v)
        {
            num[i]=dp[x][t1];
            t1++;
        }
        else
        {
            num[i]=dp[x-w][t2]+v;
            t2++;
        }
    }
    for(i=1;i<=k;i++)dp[x][i]=num[i];
}
int main()
{
    int i,j,k,v,n;
    int ws[301];
    int vs[301];
    while(~scanf("%d%d%d",&k,&v,&n))
    {
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&ws[i],&vs[i]);
        }

        for(i=0;i<=v;i++)
        {
            for(j=0;j<=k;j++)
            {
                dp[i][j]=-99999999;
            }
        }
        //for(i=0;i<=v;i++)dp[i][0]=-1;
        dp[0][1]=0;
        for(i=0;i<n;i++)
        {
           // cout<<"-------------"<<endl;
            for(j=v;j>=ws[i];j--)
            {
                add(j,k,ws[i],vs[i]);
            }
        }
        int ns=0;
        for(i=1;i<=k;i++)
        {
            if(dp[v][i]<=0)break;
            ns+=dp[v][i];
        }
        cout<<ns<<endl;
    }
    return 0;
}


你可能感兴趣的:(rqnoj-123-多人背包-第K最优解(好题))