5429 多重背包
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
题目描述 Description
你有一个容量为M的背包,和N种物品。
每种物品都有三个属性,vi,wi,与ci,分别表示这种物品的体积、价值和件数。
你的任务是,从这些所给物品中,选出若干件,其体积之和不能超过背包容量,并且使所选物品的权值的和最大。
输入描述 Input Description
第一行两个整数N,M
接下来N行每行三个数vi,wi,ci描述第i件物品的属性
输出描述 Output Description
最大的权值和
样例输入 Sample Input
2 8
2 100 4
4 100 2
样例输出 Sample Output
400
数据范围及提示 Data Size & Hint
对于20%的数据,ci=1
对于60%的数据,N,M<=500,ci<=100
对于90%的数据,N,M<=3000
对于100%的数据,N,M<=7000,ci<=5000,保证答案不超过2147483647
解题思路:
此题若直接使用多重背包的版子会超时,需通过单调队列将其优化。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <set>
#include <utility>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define inf 0x3f3f3f3f
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
//priority_queue<int,vector<int> ,greater<int> >q;
const int maxn = (int)1e5 + 5;
const ll mod = 1e9+7;
int vi[7500],wi[7500],ci[7500];
int dp[7500];
typedef pair<int,int> p;
deque<p> qu;
int main()
{#ifndef ONLINE_JUDGE//freopen("in.txt", "r", stdin);#endif//freopen("out.txt", "w", stdout);//ios::sync_with_stdio(0),cin.tie(0);int N,M;scanf("%d %d",&N,&M);rep(i,1,N) scanf("%d %d %d",&vi[i],&wi[i],&ci[i]);for(int i=1;i<=N;i++) {int v=vi[i],w=wi[i],c=ci[i];for(int d=0;d<v;d++) {while(!qu.empty()) qu.pop_back();for(int j=0;j<=(M-d)/v;j++) {if(j-qu.front().first>c) qu.pop_front();while(!qu.empty()&&dp[j*v+d]-j*w>=qu.back().second)qu.pop_back();qu.push_back(p(j,dp[j*v+d]-j*w));dp[j*v+d]=qu.front().second+j*w;}}}printf("%d\n",dp[M]);return 0;
}