P1782 旅行商的背包[混合背包,优化,数据大]

P1782 旅行商的背包

题意

旅行商的背包

题目描述

小 S 坚信任何问题都可以在多项式时间内解决,于是他准备亲自去当一回旅行商。在出发之前,他购进了一些物品。这些物品共有 n n n 种,第 i i i 种体积为 V i V_i Vi,价值为 W i W_i Wi,共有 D i D_i Di 件。他的背包体积是 C C C。怎样装才能获得尽量多的收益呢?作为一名大神犇,他轻而易举的解决了这个问题。

然而,就在他出发前,他又收到了一批奇货。这些货共有 m m m 件,第 i i i 件的价值 Y i Y_i Yi 与分配的体积 X i X_i Xi 之间的关系为: Y i = a i X i 2 + b i X i + c i Y_i=a_iX_i^2+b_iX_i+c_i Yi=aiXi2+biXi+ci。这是件好事,但小 S 却不知道怎么处理了,于是他找到了一位超级神犇(也就是你),请你帮他解决这个问题。

输入格式

第一行三个数 n , m , C n,m,C n,m,C,如题中所述;

以下 n n n 行,每行有三个数 V i , W i , D i V_i,W_i,D_i Vi,Wi,Di,如题中所述;

以下 m m m 行,每行有三个数 a i , b i , c i a_i,b_i,c_i ai,bi,ci,如题中所述。

输出格式

仅一行,为最大的价值。

样例 #1
样例输入 #1
2 1 10
1 2 3
3 4 1
-1 8 -16
样例输出 #1
10
提示
样例解释

前两种物品全部选走,最后一个奇货分给 4 4 4 的体积,收益为 2 × 3 + 4 × 1 + ( − 1 ) × 16 + 8 × 4 + ( − 16 ) = 10 2 \times 3+4 \times 1+(-1) \times 16+8 \times 4+(-16)=10 2×3+4×1+(1)×16+8×4+(16)=10

限制与约定

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 4 1 \le n \le 10^4 1n104 1 ≤ m ≤ 5 1 \le m \le 5 1m5 1 ≤ C ≤ 1 0 4 1 \le C \le 10^4 1C104,$
1 \le W_i,V_i,D_i \le 1000 , , -1000 \le a_i,b_i,c_i \le 1000$。

tags

混合背包(多重背包+完全背包+任意重量背包)、快读、二进制优化

思路

  1. 数据量很大:快读
  2. 先分析任意重量背包
    1. 因为物品数只有5,可以直接暴力解决
    2. 枚举容量,对于指定的容量j,可以选重量0~j的物品,枚举这所有物品即可
  3. 重点在多重背包部分
    1. 二进制优化可能不能少**(可以直接拆分物品数量进行dp,不用存到数组中,节省空间也不用去分析数组大小)**
    2. 但是还是会超时,在优化:多重背包变为完全背包,当最多可以选i物品的数量<Di时,可以把其看作完全背包来写,二不用去拆分背包

AC代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn=1e4+10,maxm=10;
int n,m,h;
ll dp[maxn];

inline int read(){
    int x=0,j=1;char ch;ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')j=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*j;
}

int main(){
    n=read(),m=read(),h=read();
    for(int i=1;i<=n;i++){
        int x,y,z;
        x=read(),y=read(),z=read();
        if(z*x>h){
            for(int j=x;j<=h;j++)dp[j]=max(dp[j],dp[j-x]+y);
        }
        else{
            for(int k=1;k<=z;k<<=1){
                for(int j=h;j>=k*x;j--){
                    dp[j]=max(dp[j],dp[j-k*x]+k*y);
                }
                z-=k;
            }
            if(z){
                for(int j=h;j>=z*x;j--){
                    dp[j]=max(dp[j],dp[j-z*x]+z*y);
                }
            }
        }
    }
    for(int i=1;i<=m;i++){
        int a,b,c;
        a=read(),b=read(),c=read();
        for(int j=h;j>=0;j--){
            for(int k=0;k<=j;k++){
                dp[j]=max(dp[j],dp[j-k]+1ll*a*k*k+b*k+c);
            }
        }
    }
    cout<<dp[h]<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值