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

   

原文地址:https://www.cnblogs.com/starve/p/13475432.html