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;
}