給兩個樹,大小分別爲n和m,如今兩棵樹各選一些點(包括1),使得這棵樹以1號點爲根同構(同構就是每一個點的孩子數目相同),求最大的同構樹。(n, m<=500)c++
咱們從兩棵樹中各取出一個點,考慮以這兩個點爲根能獲得的最大同構數。spa
容易獲得:
設\(d(i, j)\)表示第一棵樹選\(i\)號點,第二棵樹選\(j\)號點所能獲得的最大同構數。
那麼\(d(i, j)\)就是等於從\(i\)這個點的子樹選一些點,從\(j\)這個點的子樹選一些點,選出的點數目相同,一一匹配,則答案就是這些點的\(\sum d(x, y)\)。
計算這個咱們用最大費用流來計算。
同時咱們從深度深的向深度淺的進行計算。code
#include <bits/stdc++.h> using namespace std; const int N=505, M=N*2; int ed[2][N][N], ecnt[2][N], n[2], ihead[M], cnt=1; struct E { int next, from, to, cap, w; }e[M*M]; void add(int x, int y, int cap, int w) { e[++cnt]=(E){ihead[x], x, y, cap, w}; ihead[x]=cnt; e[++cnt]=(E){ihead[y], y, x, 0, -w}; ihead[y]=cnt; } int d[M], p[M]; bool spfa(int s, int t, int n) { static bool vis[M]; static int q[M], fr, ta; fr=ta=0; q[ta++]=s; memset(d, 0x7f, sizeof(int)*(n+1)); d[s]=0; while(ta!=fr) { int x=q[fr++]; vis[x]=0; fr=fr==M?0:fr; for(int i=ihead[x]; i; i=e[i].next) { if(!e[i].cap) { continue; } int y=e[i].to; if(d[y]>d[x]+e[i].w) { d[y]=d[x]+e[i].w; p[y]=i; if(!vis[y]) { vis[y]=1; if(d[y]<d[q[fr]]) { fr=fr==0?M:fr; q[--fr]=y; } else { q[ta++]=y; ta=ta==M?0:ta; } } } } } return d[t]!=0x7f7f7f7f; } void tadd(int x, int y, int w) { ed[w][x][ecnt[w][x]++]=y; ed[w][y][ecnt[w][y]++]=x; } int st[2][N][N], scnt[2][N], mxdep; void dfs(int w, int x, int f, int dep) { st[w][dep][scnt[w][dep]++]=x; mxdep=max(dep, mxdep); int sz=0; for(int i=0; i<ecnt[w][x]; ++i) { int y=ed[w][x][i]; if(y==f) { continue; } dfs(w, y, x, dep+1); ed[w][x][sz++]=y; } ecnt[w][x]=sz; } int f[N][N]; void work(int x, int y) { int c1=ecnt[0][x], c2=ecnt[1][y]; int s=c1+c2+1, t=s+1; memset(ihead, 0, sizeof(int)*(t+1)); cnt=1; for(int i=1; i<=c1; ++i) { add(s, i, 1, 0); } for(int i=1; i<=c2; ++i) { add(c1+i, t, 1, 0); } for(int i=0; i<c1; ++i) { for(int j=0; j<c2; ++j) { int y1=ed[0][x][i], y2=ed[1][y][j]; add(i+1, c1+j+1, 1, -f[y1][y2]); } } int &now=f[x][y]; now=1; while(spfa(s, t, t)) { int f=0x7f7f7f7f; for(int x=t; x!=s; x=e[p[x]].from) f=min(f, e[p[x]].cap); for(int x=t; x!=s; x=e[p[x]].from) e[p[x]].cap-=f, e[p[x]^1].cap+=f; now+=-f*d[t]; } } void dfs(int dep) { if(dep<0) { return; } int c1=scnt[0][dep], c2=scnt[1][dep]; for(int i=0; i<c1; ++i) { for(int j=0; j<c2; ++j) { work(st[0][dep][i], st[1][dep][j]); } } dfs(dep-1); } int main() { scanf("%d", &n[0]); for(int i=1; i<n[0]; ++i) { int x, y; scanf("%d%d", &x, &y); tadd(x, y, 0); } scanf("%d", &n[1]); for(int i=1; i<n[1]; ++i) { int x, y; scanf("%d%d", &x, &y); tadd(x, y, 1); } dfs(0, 1, 0, 0); dfs(1, 1, 0, 0); dfs(mxdep); printf("%d\n", f[1][1]); return 0; }