Processing math: 100%

Luogu P1858 多人背包

P1858 多人背包

题意

题目描述

01背包前k优解的价值和

输入输出格式

输入格式:

第一行三个数KVN

接下来每行两个数,表示体积和价值

输出格式:

k优解的价值和

输入输出样例

输入样例#1:

2 10 5
3 12
7 20
2 4
5 6
1 1

输出样例#1:

57

说明

对于100%的数据,K50,V5000,N200

思路

让我先秒了这道水题。 --Mercury

多重背包。考场上考到的时候使用的是STL中的优先队列求解,即对于每一个V状态开一个优先队列,更新时逐个取出再插入,超过50个时后面的不用再插回去了。

这是一种显然的蚊子打高射炮高射炮打蚊子的做法,我们不妨这么想:

对于一般的01背包问题,我们有标准的状态转移方程f[i]=max(f[i],f[iv[j]]+w[j])(iv[j])。也就是说,对于每个物品而言,状态f[i]只与f[i]f[iv[j]]有关,所以我们不妨设计f[i][j]表示f[i]的第j优解,更新时因为f[i][j]是有单调性的,所以拿单调指针从左往右扫一遍,扫出k个最优解,来更新就好了:

for(int i=V;i>=v[j];i--)//01背包倒序枚举
{
    int cnt=0,cfr=0,cto=0;//cnt记录更新后的解,cto记录更新前的解,cfr记录f[i-v[j]]的解
    while(cnt<k)//找到k个解
        if(f[i][cto]>f[i-v[j]][cfr]+w[j]) tmp[cnt++]=f[i][cto++];//扫描
        else tmp[cnt++]=f[i-v[j]][cfr++]+w[j];
    for(int w=0;w<k;w++) f[i][w]=tmp[w];//更新
}

AC代码

#include<bits/stdc++.h>
using namespace std;
int k,v,n,ans,f[5005][55],tmp[55];
int read()
{
    int re=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
    return re;
}
int main()
{
    k=read(),v=read(),n=read();
    memset(f,0xcf,sizeof f);
    f[0][0]=0;
    while(n--)
    {
        int x=read(),y=read();
        for(int i=v;i>=x;i--)
        {
            int cnt=0,cfr=0,cto=0;
            while(cnt<k)
                if(f[i][cto]>f[i-x][cfr]+y) tmp[cnt++]=f[i][cto++];
                else tmp[cnt++]=f[i-x][cfr++]+y;
            for(int j=0;j<k;j++) f[i][j]=tmp[j];
        }
    }
    for(int i=0;i<k;i++) ans+=f[v][i];
    printf("%d",ans);
    return 0;
}
posted @   UranusITS  阅读(111)  评论(0编辑  收藏  举报
编辑推荐:
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
阅读排行:
· 官方的 MCP C# SDK:csharp-sdk
· 一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
· 提示词工程师自白:我如何用一个技巧解放自己的生产力
· 一文搞懂MCP协议与Function Call的区别
· 如何不购买域名在云服务器上搭建HTTPS服务
点击右上角即可分享
微信分享提示