【[SDOI2008]山贼集团】

非常好的一道题

树上的状压\(dp\)

根据数据范围我们就能知道这是一道需要状压的题目

所以状态就是\(dp[i][S]\)表示在以\(i\)为根的子树里,选择的状态为\(S\)的最大收益

这个收益只是在子树内部的收益,我们往上转移的时候继续加

显然这个东西类似于一个树上背包,我们子树和根顺次合并就好了

由于这里的体积是状态,所以我们可以直接枚举子集进行转移

方程

\[dp[i][s]=max(dp[j][t]+dp[i][s\ xor\ t]) \]

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#define re register
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define lowbit(x) ((x)&(-x))
struct E
{
    int v,nxt;
}e[201];
inline int read()
{
    char c=getchar();
    int x=0,r=1;
    while(c<'0'||c>'9') {if(c=='-') r=-1;c=getchar();}
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x*r;
}
int deep[101],head[101];
int map[101][13];
int num,M,n,m,ans=-999999999;
inline void add_edge(int x,int y)
{
    e[++num].v=y;
    e[num].nxt=head[x];
    head[x]=num;
}
int dp[101][4099],val[4099];
inline int tot(int x)
{
    int num=0;
    while(x) num++,x>>=1;
    return num;
}
void pre(int x,int fa)
{
    deep[x]=deep[fa]+1;
    for(re int i=head[x];i;i=e[i].nxt)
    if(!deep[e[i].v]) pre(e[i].v,x);
}
void dfs(int x)
{
    for(re int i=head[x];i;i=e[i].nxt)
    if(deep[e[i].v]>deep[x])
    {
        dfs(e[i].v);
        for(re int s=M;s;s--)
            for(re int t=s;t;t=t=(t-1)&s)
                dp[x][s]=max(dp[x][s],dp[x][s^t]+dp[e[i].v][t]);
    }
    for(re int s=0;s<=M;s++)
    	dp[x][s]+=val[s];
}
int main()
{
    n=read(),m=read();
    int x,y;
    for(re int i=1;i<n;i++)
        x=read(),y=read(),add_edge(x,y),add_edge(y,x);
    M=(1<<m)-1;
    for(re int i=1;i<=n;i++)
    {
        for(re int j=1;j<=m;j++)
            map[i][j]=read();
        for(re int j=1;j<=M;j++)
            dp[i][j]=dp[i][j^lowbit(j)]-map[i][tot(lowbit(j))];
    }
    int T=read();
    int V,C;
    while(T--)
    {
        int s=0,x=0;
        V=read(),C=read();
        for(re int i=1;i<=C;i++)
            x=read(),s|=(1<<(x-1));
        int p=s^M;
        for(re int t=p;t;t=(t-1)&p)
            val[(t|s)]+=V;
        val[s]+=V;
    }
    pre(1,0);
    dfs(1);
    std::cout<<dp[1][M];
    return 0;
}
posted @ 2019-01-01 21:36  asuldb  阅读(227)  评论(0编辑  收藏  举报