hdu 2191 (多重揹包的單調隊列優化)

  多重揹包單調隊列優化是思想是。普通的dp爲

dp[i][j]=max{dp[i-1][j-k*v[i]]+k*w[i]};

其實你可以發現對能更新j是j和一個剩餘類。也就是 

0, v[i],2v[i],3v[i] ,4v[i]...

1 ,1+v[i],1+2v[i],1+3v[i]

...........

v[i]-1,2*v[i]-1......

更新值存在一個剩餘類中,組與組之間不存在更新。那麼實際上我們可以寫dp寫好這樣

dp[b+x*v[i]]=max{ dp[b+k*v[i]]+(x-k)*w[i] }=max{dp[b+k*v[i]]-k*w[i]}+x*w[i] ;  (x-c[i]<=k && k<=x)

實際上一個j對於一個x和b,那麼可以看出實際上就是機率一段x之前的c[i]區間內的最值。這是一個很明顯的單調隊列優化。

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
const int mmax  = 1000010;
const int inf = 0x3fffffff;
int p[110],h[110],c[110];
int dp[110][110];
int Q[110];
int head,tail;
void add(int b,int i,int k)
{
    while(head<tail &&
          dp[i-1][b+Q[tail-1]*p[i]]-Q[tail-1]*h[i]<=dp[i-1][b+k*p[i]]-k*h[i])
        tail--;
    Q[tail++]=k;
}
int main()
{
    int n,m,T;
    cin>>T;
    while(T--)
    {
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d %d %d",&p[i],&h[i],&c[i]);
        memset(dp,0,sizeof dp);
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<p[i];j++)
            {
                head=tail=0;
                for(int k=0;j+k*p[i]<=n;k++)
                {
                    add(j,i,k);
                    if( k-c[i]-1== Q[head] )
                    {
                        head++;
                    }
                    dp[i][j+k*p[i]]=dp[i-1][j+Q[head]*p[i]]-Q[head]*h[i]+k*h[i];
                }
            }
        }
        int ans=0;
        for(int i=0;i<=n;i++)
            ans=max(ans,dp[m][i]);
        cout<<ans<<endl;

    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章