BZOJ2368 : Modern Art Plagiarism 樹同構

Claris發表於2017-07-11

列舉$T_1$的樹根,然後DP,設$f[i][j]$表示$T_1$的子樹$i$是否存在包括i的連通子樹與$T_2$的子樹$j$同構。

若$j$是葉子,那麼顯然可以。

若$deg_i<deg_j$,那麼顯然不可以。

否則將$i$與$j$所有互相同構的兒子之間連邊,二分圖匹配判斷是否存在完美匹配即可。

 

#include<cstdio>
#include<algorithm>
const int N=105;
int T,C,n,m,o,i,j,k,x,y;
int g[N],v[N<<1],nxt[N<<1],ed,f[N],d[N],deg[N],q[N];
int G[N],V[N<<1],NXT[N<<1],ED,F[N],D[N],DEG[N],Q[N];
bool dp[N][N],ok[N][N],b[N];int p[N];
inline bool cmp(int x,int y){return d[x]>d[y];}
inline bool CMP(int x,int y){return D[x]>D[y];}
inline void add(int*g,int*v,int*nxt,int&ed,int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x,int y,int*f,int*d,int*deg,int*g,int*v,int*nxt){
  f[x]=y,d[x]=d[y]+1;deg[x]=0;
  for(int i=g[x];i;i=nxt[i])if(v[i]!=y)deg[x]++,dfs(v[i],x,f,d,deg,g,v,nxt);
}
bool find(int x){
  for(int i=1;i<=o;i++)if(!b[i]&&ok[x][i]){
    b[i]=1;
    if(!p[i]||find(p[i]))return p[i]=x,1;
  }
  return 0;
}
inline void DP(int x,int y){
  dp[x][y]=0;
  if(deg[x]<DEG[y])return;
  if(!DEG[y]){dp[x][y]=1;return;}
  int n=o=0,i,j,cnt=0;
  static int A[N],B[N];
  for(i=g[x];i;i=nxt[i])if(v[i]!=f[x])A[++n]=v[i];
  for(i=G[y];i;i=NXT[i])if(V[i]!=F[y])B[++o]=V[i];
  for(i=1;i<=n;i++)for(j=1;j<=o;j++)ok[i][j]=dp[A[i]][B[j]];
  for(i=1;i<=o;i++)p[i]=0;
  for(i=1;i<=n;i++){
    for(j=1;j<=o;j++)b[j]=0;
    if(find(i)){
      cnt++;
      if(cnt==o){dp[x][y]=1;return;}
    }
  }
}
bool solve(){
  scanf("%d",&n);
  for(ed=0,i=1;i<=n;i++)g[i]=0,q[i]=i;
  for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(g,v,nxt,ed,x,y),add(g,v,nxt,ed,y,x);
  scanf("%d",&m);
  for(ED=0,i=1;i<=m;i++)G[i]=0;
  for(i=1;i<m;i++)scanf("%d%d",&x,&y),add(G,V,NXT,ED,x,y),add(G,V,NXT,ED,y,x);
  dfs(1,0,F,D,DEG,G,V,NXT);
  for(i=1;i<=m;i++)Q[i]=i;
  std::sort(Q+1,Q+m+1,CMP);
  for(i=1;i<=n;i++){
    dfs(i,0,f,d,deg,g,v,nxt);
    std::sort(q+1,q+n+1,cmp);
    for(j=1;j<=n;j++)for(k=1;k<=m;k++)DP(q[j],Q[k]);
    if(dp[i][1])return 1;
  }
  return 0;
}
int main(){
  for(scanf("%d",&T);T--;puts(solve()?"YES":"NO"));
  return 0;
}

  

相關文章