《情報学奥赛一本通》例9.13慶功会


【質問の説明】学級別学校体育会で全校1位を獲得したことを祝うため、担任は祝賀会を開くことを決め、そのために賞品を購入して選手をねぎらう.最大価値の賞品を購入することを期待し、精力と体力を補うことができる.【入力フォーマット】1行2個数n(n<=500)、m(m<=6000)このうちnは購入希望の賞品の数を表し,mは送金金額を表す.次のn行は、各行3個の数、v、w、sは、それぞれI番目の賞品の価格、価値(価格と価値は異なる概念)と購入数(0個からs個まで可能)を示し、そのうちv<=100、w<=1000、s<=10.【出力フォーマット】1行目:1個の数は、今回の購入で得られる最大の価値(注意!価格ではない)を示す.
単調なキューは多重リュックサックテンプレートの問題を最適化します.
#include
#include
int max(int x,int y)
{
    return x>y?x:y;
}
int dp[510][6010],que[6010],v[510],w[510],c[510];
int main()
{
    freopen("party.in","r",stdin);
    freopen("party.out","w",stdout); 
    int i,j,k,l,m,n,p,q,x,y,z,hd,tl;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++)
      scanf("%d%d%d",&v[i],&w[i],&c[i]);
    for (i=1;i<=n;i++)
      for (j=0;j1;
        tl=0;
        for (k=0;k*v[i]+j<=m;k++)
        {
            while (hd<=tl&&k-que[hd]>c[i]) hd++;
            while (hd<=tl&&dp[i-1][k*v[i]+j]-k*w[i]>=dp[i-1][que[tl]*v[i]+j]-que[tl]*w[i]) tl--;
            que[++tl]=k;
            dp[i][k*v[i]+j]=dp[i-1][que[hd]*v[i]+j]+w[i]*(k-que[hd]);
        }
      }
    printf("%d
"
,dp[n][m]); }