• 洛咕 P2465 [SDOI2008]山贼集团


    裸的状压dp。

    设f[i][j]表示在i字数内放j集合的分部,直接sb转移。

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define il inline
    #define vd void
    typedef long long ll;
    il int gi(){
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    int n,p,fir[101],dis[201],nxt[201],id;
    il vd link(int a,int b){nxt[++id]=fir[a],fir[a]=id,dis[id]=b;}
    int W[101][13],WW[101][1<<12],s[1<<12],S[1<<12],lg[1<<12];
    int f[101][1<<12],F[1<<12],G[1<<12],U;
    il vd dfs(int x,int fa=-1){
        for(int i=fir[x];i;i=nxt[i])if(fa!=dis[i])dfs(dis[i],x);
        memset(F,-63,sizeof F);F[0]=0;
        // F[o] 表示 放集合为o的部门的最大收益
        for(int i=fir[x];i;i=nxt[i])
            if(fa!=dis[i]){
                memcpy(G,F,sizeof F);
                for(int j=U;;j=(j-1)&U){
                    for(int k=j;;k=(k-1)&j){
                        F[j]=std::max(F[j],G[k]+f[dis[i]][j^k]);
                        if(!k)break;
                    }
                    if(!j)break;
                }
            }
        for(int i=U;;i=(i-1)&U){
            for(int j=i;;j=(j-1)&i){
                f[x][i]=std::max(f[x][i],S[i]+F[j]-WW[x][i^j]);
                if(!j)break;
            }
            if(!i)break;
        }
    }
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("2465.in","r",stdin);
        freopen("2465.out","w",stdout);
    #endif
        memset(f,-63,sizeof f);
        n=gi(),p=gi();int u,v,w;
        U=(1<<p)-1;
        for(int i=1;i<n;++i)u=gi(),v=gi(),link(u,v),link(v,u);
        for(int i=0;i<p;++i)lg[1<<i]=i;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=p;++j)W[i][j]=gi();
            for(int j=1;j<1<<p;++j)WW[i][j]=WW[i][j-(j&-j)]+W[i][lg[j&-j]+1];
        }
        int T=gi();
        while(T--){
            u=gi(),v=gi(),w=0;
            while(v--)w|=1<<gi()-1;
            s[w]+=u;
        }
        for(int i=0;i<1<<p;++i)
            for(int j=i;;j=(j-1)&i){
                S[i]+=s[j];
                if(!j)break;
            }
        dfs(1);
        printf("%d
    ",f[1][U]);
        return 0;
    }
    
  • 相关阅读:
    图片懒加载DEMO
    手写offset函数
    DOM
    jQuery笔记
    children和 childNodes辨析
    运算符...典型的三种用处
    Python中的数据结构---栈,队列
    手写call方法
    移动零元素--leetcode题解总结
    剑指 Offer 36. 二叉搜索树与双向链表
  • 原文地址:https://www.cnblogs.com/xzz_233/p/9804474.html
Copyright © 2020-2023  润新知