【hdu2191】 单调队列优化多重背包板题
发现自己不仅树上背包不会,泛背包不会,啥都不会,最后发现基础的单调队列优化多重背包都不会,真是太弱了!
HDU 2191
大致题意:就是裸的多重背包求价值最大
对于多重背包,我们可以考虑其最朴素的方法,将其转化成普通的01背包,那么时间复杂度显然是爆炸的,O(物品个数*背包容积)
事实上,我们可以利用单调队列,将其时间复杂度优化成O(物品种类数*背包容积)
具体的实现可以见NOI2009集训队论文xch的<<浅谈几类背包题>>和<<背包九讲>>
大致原理是,我们发现对于一个容积i,对于一个物品大小j,其可以取的DP状态转移是i-j*k(1<=k<=n),而我们可以发现,对于相同的(i%物品大小),即每次容积考虑都增加物品大小v,其就是一个滑动窗口模型!
于是我们就可以利用单调队列优化,将一个物品余数相同的一起考虑,最终对于一个物品时间复杂度就是O(背包容积)
参考博客:https://blog.csdn.net/hhz6830975/article/details/79436320
talk is cheap , show me code ! :
#include<iostream> #include<cstdio> #include<queue> #include<algorithm> #include<cmath> #include<cstring> #define mp make_pair using namespace std; const int maxn = 205; int C,n,v,w; deque<pair<int,int> > q; int dp[maxn]; int main() { scanf("%d",&C); int N,M; while(C--) { scanf("%d%d",&N,&M); memset(dp,0,sizeof dp); for(int i=1;i<=M;i++) { scanf("%d%d%d",&v,&w,&n); for(int o=0;o<v;o++) { while(q.size()) q.pop_back(); for(int j=0;j<=(N-o)/v;j++) { int tmp = dp[o+j*v]-j*w; while(q.size()&&tmp>=q.back().first) q.pop_back(); q.push_back(mp(tmp,j)); while(q.front().second<j-n) q.pop_front(); dp[o+j*v] = q.front().first + j*w; } } } printf("%d\n",dp[N]); } }