[ZOJ 3812 We Need Medicine] DP

题目

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3812

分析

  最裸的dp就是f[i][j][k],然后把k压成二进制变成f[i][j]。   K用bitset呀200000那维。

然后将i/10  输出时2^10暴力。

代码

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<bitset>

using namespace std;
typedef bitset<200010> bs;
bs g[45][55];
int d2[31],w[2100],t[2100],n,q,tot,ans[2100],T,m;
int dfs2(int a,int b,int c,int d,int e,int f,int ww)
{
    if(e>b||f>ww) return 0;
    if(c+d>n||d>10) return g[a-1][b-e][ww-f];
    int k=dfs2(a,b,c,d+1,e,f,ww);
    if(k&1) return k;
    return dfs2(a,b,c,d+1,e+w[c+d],f+t[c+d],ww)|d2[d];
}
int main()
{
    scanf("%d",&T);
    d2[0]=1; for(int i=1;i<=21;++i) d2[i]=d2[i-1]<<1;
    while(T--)
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;++i) scanf("%d%d",&w[i],&t[i]);
        m=(n-1)/10+1;
        g[0][0].set(0);
        for(int i=1;i<=m;++i)
        {
            for(int j=0;j<=50;++j) g[i][j]=g[i-1][j];
            for(int j=(i-1)*10+1;j<=min(i*10,n);++j)
              for(int k=50;k>=w[j];--k)
              {
                  bs tt=g[i][k-w[j]]<<t[j];
                  g[i][k]|=tt;
              }
        }
        while(q--)
        {
            int a,b; tot=0;
            scanf("%d%d",&a,&b);
            if(g[m][a][b])
            {
                for(int i=m;i;--i)
                {
                    int k=dfs2(i,a,(i-1)*10,1,0,0,b);
                    k>>=1;
                    for(int j=1;k;k>>=1,++j)
                      if(k&1)
                        ans[++tot]=(i-1)*10+j,
                        a-=w[ans[tot]],b-=t[ans[tot]];
                }
                sort(ans+1,ans+tot+1);
                for(int i=1;i<tot;++i) printf("%d ",ans[i]);
                printf("%d\n",ans[tot]);
            }
            else printf("No solution!\n");
        }
    }
    return 0;
}


你可能感兴趣的:([ZOJ 3812 We Need Medicine] DP)