zoukankan      html  css  js  c++  java
  • J Identical Trees(求俩个树转化所需的最小代价,hash判同构,费用流求转移代价)

    题:https://ac.nowcoder.com/acm/contest/5675/J

    题意:给定T1,T2的有根树,问T1能最少改变多少个节点而变成根节点和T2相同,同时每个节点的父亲节点和T2一样。(要保持变换后T1节点仍是1~n出现1次),题目保证至少有一种可以转化。

    分析:考虑dp[i][j]为节点 i 变换为节点 j 的最小代价。i 要转化成 j 的条件就是T1树的 i 节点子树要和T2树的 j 节点子树要同构,这部分用树hash来判断即可。(虽然这部分本人测试过只判断子树大小就可以通过,但这么判断说不通,只有判断是否同构才是正确的)

       若同构,则考虑T1树的 i 节点的儿子每一个都和T2树的 j 节点的儿子进行匹配,看最小代价为多少,这部分用费用流来实现(难怪n设这么小)费用为dfs之前计算的dp值。

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    typedef long long ll;
    const int M=2e5+5;
    const int inf=0x3f3f3f3f;
    int book[M+10],prim[M+10],num;
    void initprim(){
        for(int i=2;i<M;i++){
            if(!book[i])prim[++num]=i;
            for(int j=1;j<=num&&1ll*prim[j]*i<M;j++){
                book[prim[j]*i]=1;
                if(i%prim[j]==0)
                    break;
            }
        }
    }
    struct node{
        int v,w,cost,nextt;
    }e[M];
    int mincost;
    int head[M],cur[M],dis[M],vis[M],tot,s,t;
    int init(int nn){
        s=1,t=nn;
        for(int i=0;i<=t;i++)
            head[i]=-1;
        tot=0;
        mincost=0;
    }
    void addedge(int u,int v,int w,int cost){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].cost=cost;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].cost=-cost;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    bool bfs(){
        for(int i=0;i<=t;i++)
            dis[i]=inf;
        queue<int>que;
        que.push(s);
        dis[s]=0;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            vis[u]=0;
            for(int i=head[u];~i;i=e[i].nextt){
                int v=e[i].v;
                if(e[i].w&&dis[u]+e[i].cost<dis[v]){
                    dis[v]=dis[u]+e[i].cost;
                    if(!vis[v]){
                        vis[v]=1;
                        que.push(v);
                    }
                }
            }
        }
        return dis[t]!=inf;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int ans=0;
        vis[u]=1;
        for(int i=cur[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(dis[v]==dis[u]+e[i].cost&&!vis[v]&&e[i].w){
                cur[u]=i;
                int x=dfs(v,min(e[i].w,fl-ans));
                e[i].w-=x;
                e[i^1].w+=x;
                ans+=x;
                mincost+=x*e[i].cost;
                if(ans==fl)
                    break;
            }
        }
        vis[u]=0;
        return ans;
    }
    void MCMF(){
        while(bfs()){
            for(int i=0;i<=t;i++)
                cur[i]=head[i];
            dfs(s,inf);
        }
    }
    const int N=600;
    int sz1[N],sz2[N],dp[N][N];
    unsigned long long h1[N],h2[N];
    vector<int>g1[N],g2[N];
    void dfs1(int u){
        sz1[u]=1,h1[u]=1;
        if(!g1[u].size()){
            h1[u]=1;
            return ;
        }
        h1[u]=0;
        for(auto v:g1[u]){
            dfs1(v);
            sz1[u]+=sz1[v];
        }
        for(auto v:g1[u]){
            h1[u]+=h1[v]*prim[sz1[v]];
        }
        h1[u]*=sz1[u];
    }
    void dfs2(int u){
        sz2[u]=1;h2[u]=1;
        if(!g2[u].size()){
            h2[u]=1;
            return;
        }
        h2[u]=0;
        for(auto v:g2[u]){
            dfs2(v);
            sz2[u]+=sz2[v];
        }
        for(auto v:g2[u])h2[u]+=h2[v]*prim[sz2[v]];
    
        h2[u]*=sz2[u];
    }
    void solve(int x,int y){
        if(h1[x]!=h2[y])return;
        if(sz1[x]==1){
            dp[x][y]=(x!=y);
            return ;
        }
        for(auto l:g1[x])
            for(auto r:g2[y])
                solve(l,r);
        init(2+g1[x].size()+g2[y].size());
        for(int i=0;i<(int)g1[x].size();i++){
            addedge(s,i+2,1,0);
            for(int j=0;j<(int)g2[y].size();j++){
                int tx=g1[x][i],ty=g2[y][j];
                addedge(i+2,j+1+g1[x].size()+1,1,dp[tx][ty]);
            }
        }
        for(int i=0;i<(int)g2[y].size();i++)
            addedge(i+1+g1[x].size()+1,t,1,0);
        MCMF();
        dp[x][y]=min(dp[x][y],mincost+(x!=y));
        return ;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0),cout.tie(0);
        initprim();
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dp[i][j]=n;
        int rt1,rt2;
        for(int x,i=1;i<=n;i++){
            cin>>x;
            if(x)g1[x].pb(i);
            else rt1=i;
        }
        for(int x,i=1;i<=n;i++){
            cin>>x;
            if(x)g2[x].pb(i);
            else rt2=i;
        }
        dfs1(rt1),dfs2(rt2);
        solve(rt1,rt2);
        cout<<dp[rt1][rt2]<<'
    ';
        return 0;
    }
    View Code

       

  • 相关阅读:
    Leetcode 238. Product of Array Except Self
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 290. Word Pattern
    Leetcode 205. Isomorphic Strings
    Leetcode 107. Binary Tree Level Order Traversal II
    Leetcode 102. Binary Tree Level Order Traversal
    三目运算符
    简单判断案例— 分支结构的应用
    用switch判断月份的练习
    java基本打印练习《我行我素购物系统》
  • 原文地址:https://www.cnblogs.com/starve/p/13475432.html
Copyright © 2011-2022 走看看