codevs5429 多重背包【多重背包+单调队列】

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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 ,greater >q;
const int maxn = (int)1e5 + 5;
const ll mod = 1e9+7;
int vi[7500],wi[7500],ci[7500];
int dp[7500];
typedef pair p;
deque

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

你可能感兴趣的:(背包问题,单调队列)