zoukankan      html  css  js  c++  java
  • BZOJ 3197: [Sdoi2013]assassin 树形DP + 最小费用流 + 树的同构

    Description

    Input

    Output

    其实就是给出两颗树,求一种两种树同构的方式,使得不同颜色个数最少$.$
    树的重新构建,其实就是指定不同的点为根节点$.$
    好在树的重心有一个重要的性质:在一颗树上只有一个/两个点之间又一条边$.$
    我们可以把第一棵树随便一个重心为根,求出每个点为根节点时的哈希值$.$
    再枚举第二棵树的重心,如果这个重心为根的哈希值与第一个树根的哈希值相同,说明两个树以这两个点为根的形状是相同的,我们就可以进行DP$.$
    令 $f[a][b]$ 表示 $a$ 为根与 $b$ 为根的子树进行匹配的最小代价(最少不同个数)$.$
    当然,必须满足 $a$ 与 $b$ 的子树形态相同$.$
    有一个问题:$a$ 的若干个儿子与 $b$ 的若干个儿子的哈希值都相同,那我们该怎么进行匹配呢?因为显然,只能是两两一一配对$.$
    先求出 $a$ 的所有儿子与 $b$ 的所有儿子匹配的最小代价 $f[son[a]][son[b]]$.
    发现这其实是一个二分图模型,即二分图最小匹配.
    将儿子哈希值相同的连边,跑一个最小费用流就能帮助我们决策出哪两个匹配是最优的$.$
    这么递归下去即可$.$
    感觉好多题都是这种套路:很难通过人脑进行决策,那就直接让某些特定的算法(如网络流,最小生成树)来帮我们进行一个决策$.$

    // luogu-judger-enable-o2
    #include <cstdio> 
    #include <cstring> 
    #include <algorithm>    
    #include <vector>  
    #include <queue>       
    #define ll long long      
    #define inf 1000              
    #define setIO(s) freopen(s".in", "r" , stdin)   
    using namespace std;        
    namespace MCMF 
    { 
        #define maxn 40  
        struct Edge
        {
            int from,to,cap,cost; 
            Edge(int a=0,int b=0,int c=0,int d=0):from(a),to(b),cap(c),cost(d){} 
        }; 
        queue<int>Q; 
        vector<Edge>edges; 
        vector<int>G[maxn]; 
        int d[maxn],flow2[maxn],inq[maxn],pre[maxn],s,t,ans; 
        inline void addedge(int u,int v,int c,int d) 
        {
            edges.push_back(Edge(u,v,c,d)), edges.push_back(Edge(v,u,0,-d));   
            G[u].push_back(edges.size()-2), G[v].push_back(edges.size()-1);     
        }   
        inline int spfa() 
        {
            int i,j; 
            memset(inq,0,sizeof(inq)); 
            for(i=0;i<maxn;++i) d[i]=flow2[i]=inf;
            Q.push(s),d[s]=0,inq[s]=1; 
            while(!Q.empty()) 
            {
                int u=Q.front(); Q.pop(), inq[u]=0;      
                for(i=0;i<G[u].size();++i) 
                {
                    Edge e=edges[G[u][i]];      
                    if(d[e.to]>d[u]+e.cost&&e.cap) 
                    {
                        d[e.to]=d[u]+e.cost, pre[e.to]=G[u][i];     
                        flow2[e.to]=min(e.cap,flow2[u]);
                        if(!inq[e.to]) 
                        {
                            inq[e.to]=1;    
                            Q.push(e.to);       
                        }  
                    }
                }
            }       
            int f=flow2[t],tr=t;  
            if(f==inf) return 0;   
            edges[pre[tr]].cap-=f, edges[pre[tr]^1].cap+=f, tr=edges[pre[tr]].from;   
            while(tr!=s)   
                edges[pre[tr]].cap-=f,edges[pre[tr]^1].cap+=f,tr=edges[pre[tr]].from;    
            ans+=d[t]*f; 
            return 1;      
        } 
        inline void re() 
        {
            edges.clear(); 
            memset(pre,0,sizeof(pre));     
            for(int i=0;i<maxn;++i) G[i].clear(); 
            ans=0;             
        }
        inline int getcost() 
        {
            while(spfa()); 
            return ans;    
        }
    }; 
    const int ha=2019, mul=5589, mod=233233, N=802;        
    int n, edges,root;      
    int hd[N],nex[N<<1],to[N<<1],s1[N],s2[N],f[N][N];                       
    inline void addedge(int u,int v) 
    {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;      
    } 
    struct G 
    { 
        vector<int>sor[N];  
        int Hash[N], siz[N], mx[N],root;             
        void getroot(int u,int ff) 
        {
            siz[u]=1,mx[u]=0;     
            for(int i=hd[u];i;i=nex[i]) 
                if(to[i]!=ff) 
                    getroot(to[i],u), siz[u]+=siz[to[i]],mx[u]=max(mx[u],siz[to[i]]);   
            mx[u]=max(mx[u],n-siz[u]); 
            if(mx[u]<mx[root]) root=u;                              
        }   
        void calc(int u,int ff) 
        {
            sor[u].clear(), Hash[u]=ha;    
            for(int i=hd[u];i;i=nex[i]) 
                if(to[i]!=ff)   
                    calc(to[i],u), sor[u].push_back(Hash[to[i]]);       
            sort(sor[u].begin(),sor[u].end());       
            for(int i=0;i<sor[u].size();++i) Hash[u]=((Hash[u]*mul)^sor[u][i])%mod;                             
        }  
    }t[6];     
    vector<int>c1[N],c2[N];      
    int solve(int x,int fx,int y,int fy,int ty) 
    {   
        if(f[x][y]!=-1) return f[x][y];   
        f[x][y]=s1[x]^s2[y];                   
        int i,j,nn=0;                             
        for(i=hd[x];i;i=nex[i]) 
        { 
            if(to[i]==fx) continue;           
            for(j=hd[y];j;j=nex[j]) 
            { 
                if(to[j]==fy) continue;    
                if(t[0].Hash[to[i]]==t[ty].Hash[to[j]])  
                    solve(to[i],x,to[j],y,ty); 
            }
        }           
        c1[x].clear(),c2[x].clear(); 
        for(i=hd[x];i;i=nex[i]) if(to[i]!=fx) ++nn, c1[x].push_back(to[i]); 
        for(i=hd[y];i;i=nex[i]) if(to[i]!=fy) c2[x].push_back(to[i]);   
        MCMF::re();  
        for(i=0;i<c1[x].size();++i) 
            for(j=0;j<c2[x].size();++j) 
                if(t[0].Hash[c1[x][i]]==t[ty].Hash[c2[x][j]]) 
                    MCMF::addedge(i+1,j+1+nn,1,f[c1[x][i]][c2[x][j]]);            
        MCMF::s=0,MCMF::t=nn+c2[x].size()+1;                
        for(i=1;i<=nn;++i) MCMF::addedge(0,i,1,0);             
        for(i=1;i<=c2[x].size();++i) MCMF::addedge(nn+i,nn+c2[x].size()+1,1,0);       
        f[x][y]+=MCMF::getcost();     
        return f[x][y];          
    }
    int main() 
    {
        int i,j,ans,ty=0;         
        // setIO("input"); 
        scanf("%d", &n);   
        for(i=1;i<n;++i) 
        {
            int a, b; 
            scanf("%d%d",&a,&b),addedge(a,b),addedge(b,a);          
        }
        for(i=1;i<=n;++i) scanf("%d",&s1[i]); 
        for(i=1;i<=n;++i) scanf("%d",&s2[i]);  
        t[0].mx[0]=n, t[0].getroot(1,0), t[0].calc(t[0].root,0);        
        for(ans=n,i=1;i<=n;++i) 
            if(t[0].mx[i]==t[0].mx[t[0].root]) 
            {  
                ++ty;      
                t[ty].calc(i, 0);     
                if(t[ty].Hash[i]==t[0].Hash[t[0].root]) 
                {   
                    memset(f,-1,sizeof(f));        
                    ans=min(ans,solve(t[0].root,0,i,0,ty));     
                }
            }
        printf("%d
    ",ans);    
        return 0 ; 
    }
    

      

  • 相关阅读:
    ES6 数组下
    ES6 ---数组(上部分)
    ES6---函数
    ES6---字符串
    自适应网页设计(Responsive Web Design)
    HTML Meta中添加X-UA-Compatible和IE=Edge,chrome=1有什么作用?
    mysql潜在的危险kill
    shell脚本加密
    Linux安全知识总结
    nginx 解决400 bad request 的方法(转载)
  • 原文地址:https://www.cnblogs.com/guangheli/p/11376130.html
Copyright © 2011-2022 走看看