【DP专题】——旅行商的背包

链接:https://www.luogu.org/problemnew/show/P1782

个人看来,这道题是一道非常好的多重和完全背包练手题。

题目描述

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

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

输入输出格式

输入格式:

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

以下n行,每行有三个数Vi,Wi,Di,如题中所述;

以下m行,每行有三个数ai,bi,ci,如题中所述。

输出格式:

仅一行,为最大的价值。

既然谈到背包,那么我们来把基本的几个背包复习一遍:

1.01背包:

  不用多说,01背包就是对于一个物品,你选或者不选,选的状态由你选之前的那个状态转移而来。

  伪代码:

for:(i) 1->n
    for: (j) maxv->v[i]
        f[j]=max ( f[j-v[i]]+w[i] )

2.完全背包:

  完全背包考虑到每个物品能装无限个,但实质上,和01背包的区别就是,状态转移不但可以从选之前的那个状态转移而来,还可以是选之后的某个状态(这样相当于重复选择),所以第二层循环要正着写:

for:(i) 1->n
    for: (j) v[i]->maxv
        f[j]=max ( f[j-v[i]]+w[i] )

3.多重背包:

  多重背包限定了物品数量,所以不能在原来的基础上增加物品,而是另起一个循环,枚举数量。

for:(i) 1->n
    for: (j) maxv->v[i]
        for:(k) 1->c[i] (k*v[i]<=j)
            f[j]=max ( f[j-k*v[i]]+k*w[i] )

其余的背包以后再说。其实是懒得写

所以接下来就有思路了吧!

但是呢这道题数据有点坑人,我们需要在基础上做一些优化。

--单调队列:

考虑用单调队列来优化:

参见滑动窗口

我们在维护最值的时候,可以用单调队列优化。

--读入优化(废话)

#include<iostream>
#include<cstdio>
using namespace std;
const int N=10010;
int n,m,cool;
int v[N],w[N],d[N];
int a[10],b[10],c[10];
int tietie[N];
int fu[N],sai[N];
int main(){
    scanf("%d%d%d",&n,&m,&cool);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&v[i],&w[i],&d[i]);
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<v[i];j++){
            for(int k=0,bu=0,ki=0;k*v[i]+j<=cool;k++){
                int matsuri=tietie[j+k*v[i]]-k*w[i];
                while(bu!=ki&&matsuri>fu[ki-1]) ki--;
                sai[ki]=k,fu[ki++]=matsuri;
                if(sai[bu]+d[i]<k) bu++;
                fu[k*v[i]+j]=fu[bu]+k*w[i];
            }
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=cool;j>=0;j--){
            for(int k=0;k<=j;k++){
                if(tietie[j]<tietie[j-k]+(k*a[i]+b[i])*k+c[i]) tietie[j]=tietie[j-k]+(k*a[i]+b[i])*k+c[i];
            }
        }
    }
    printf("%d",tietie[cool]);
    return 0;
} 

奇怪的是没有过,所以暂时放这了,以后再改。

 

——抓住了时间,却不会利用的人,终究也逃不过失败的命运。
原文地址:https://www.cnblogs.com/Nelson992770019/p/11240495.html