【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]);
    }
}
 
posted @ 2018-08-01 21:55  Newuser233  阅读(6)  评论(0)    收藏  举报