zoukankan      html  css  js  c++  java
  • 【Luogu】P2465山贼集团(树形状压DP)

      题目链接

      写了个70分暴力还挂了,第一遍提交只拿了十分……海星

      首先建虚拟节点多叉树转成二叉,然后子集枚举DP

      设g[x][i]是以x为根的子树内山贼集合i,x啥都不选也没贡献的时候的最大价值

      f[x][i]是要求的答案

      然后状压DP即可。

    #include<cstdio>
    #include<algorithm>
    #include<cctype>
    #include<cstring>
    #include<cstdlib>
    #define maxn 200
    #define maxp 13
    using namespace std;
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    struct Edge{
        int next,to;
    };
    
    struct Pic{
        Edge edge[maxn*200];
        int head[maxn*100],num;
        Pic(){num=0;}
        void add(int from,int to){
            edge[++num]=(Edge){head[from],to};
            head[from]=num;
        }
    }Old,New;
    
    int cst[maxn][maxn];
    int tot;
    int mon[1<<maxp];
    int dl[maxn],ndl[maxn*100];
    int f[maxn*3][1<<maxp];
    int g[maxn*3][1<<maxp];
    int cost[maxn][1<<maxp];
    int vl[1<<maxp];
    int n,p;
    
    void chan(int x,int fa){
        int now=x;
        for(int i=Old.head[x];i;i=Old.edge[i].next){
            int to=Old.edge[i].to;
            if(to==fa)    continue;
            if(ndl[now]==0||(ndl[now]==1&&dl[x]==1)){
                New.add(now,to);
                ndl[now]++;    dl[x]--;
            }
            else{
                New.add(now,++tot);
                now=tot;
                New.add(now,to);
                ndl[now]++;    dl[x]--;
            }
            chan(to,x);
        }
    }
    
    void dfs(int x,int fa){
        int lson=0,rson=0;
        f[x][0]=0;
        g[x][0]=0;
        for(int i=New.head[x];i;i=New.edge[i].next){
            int to=New.edge[i].to;
            if(to==fa)    continue;
            if(lson==0)    lson=to;
            else        rson=to;
            dfs(to,x);
        }
        if(x>n){
            if(rson==0){
                for(int i=1;i<(1<<p);++i)    f[x][i]=g[x][i]=f[lson][i];
                return;
            }
            for(int i=1;i<(1<<p);++i){
                for(int j=i;j;j=(j-1)&i)
                        g[x][i]=max(g[x][i],f[lson][j]+f[rson][i^j]);
                g[x][i]=max(g[x][i],f[lson][0]+f[rson][i]);
                    f[x][i]=g[x][i];
                }
          }
        else{
            if(rson==0){
                for(int i=1;i<(1<<p);++i){
                    g[x][i]=f[lson][i];
                    f[x][i]=g[x][i]+mon[i];
                }
                for(int i=1;i<(1<<p);++i)
                    for(int j=i;j;j=(j-1)&i)
                        f[x][i]=max(f[x][i],g[x][i^j]-cost[x][j]+mon[i]);
                return;
            }
            for(int i=1;i<(1<<p);++i){
                for(int j=i;j;j=(j-1)&i)
                        g[x][i]=max(g[x][i],f[lson][j]+f[rson][i^j]);
                g[x][i]=max(g[x][i],f[lson][0]+f[rson][i]);
                    f[x][i]=g[x][i]+mon[i];
                }
            for(int i=1;i<(1<<p);++i)
                for(int j=i;j;j=(j-1)&i){
                    int costx=cost[x][j],state=i^j;
                    f[x][i]=max(f[x][i],g[x][state]+mon[i]-costx);
                }
                
        }
    }
    
    int main(){
        memset(f,-127/3,sizeof(f));
        memset(g,-127/3,sizeof(g));
        g[0][0]=0;
        f[0][0]=0;
        n=read(),p=read();
        tot=n;
        for(int i=1;i<n;++i){
            int from=read(),to=read();
            Old.add(from,to);
            Old.add(to,from);
            dl[from]++;    dl[to]++;
        }
        for(int i=2;i<=n;++i)    dl[i]--;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=p;++j)    cst[i][j]=read();
        int T=read();
        while(T--){
            int val=read(),cnt=read(),state=0;
            for(int i=1;i<=cnt;++i){
                int x=read();
                state|=(1<<(x-1));
            }
            vl[state]+=val;
        }
        for(int i=1;i<(1<<p);++i)
            for(int j=i;j;j=(j-1)&i)    mon[i]+=vl[j];
        for(int i=1;i<=n;++i)
            for(int j=1;j<(1<<p);++j){
                int costx=0;
                for(int k=1;k<=p;++k)
                    if(j&(1<<(k-1)))    costx+=cst[i][k];
                cost[i][j]=costx;
            }
        chan(1,1);
        dfs(1,1);
        printf("%d
    ",f[1][(1<<p)-1]);
    }
    /*
    9 3
    
    1 2
    1 3
    1 4
    2 5
    3 6
    3 7
    3 8
    6 9
    
    */
  • 相关阅读:
    使用Dapper参数化查询(三) IN 查询
    cs窗体继承问题
    SVN使用教程总结(转载)
    celery——使用
    celery——简介及安装
    luffy——django中使用redis
    redis——redis入门(常用数据类型:l )
    redis——redis入门(二)
    redis——redis入门(常用数据类型:string hash)
    redis——redis入门(一)
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8980262.html
Copyright © 2011-2022 走看看