Link
假如存在某个点未被操作过,那么我们把它作为根节点。
那么此时一个点需要被操作当且仅当它在两棵树中的父亲不同。
并且我们可以得到一个限制:一个点必须在它在第一棵树中的父亲之前操作,在它在第二棵树中的父亲之后操作。
拓扑排序即可解决问题,那么剩下来的就是每个点都需要被操作的方案了。
枚举一次操作,剩下的还是按上面的做就行了。
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
const int N=57;
int read(){int x;scanf("%d",&x);return x;}
std::vector<int>e[N],g[N];
int fa[N],ndeg[N],deg[N],vis[N],mp[N][N];
void dfs(int u,int f)
{
if(fa[u]=f,vis[f]&&mp[u][f]) vis[u]=1;
for(int v:g[u]) if(v^f) dfs(v,u);
}
void work()
{
int n=read(),ans=n+1;memset(mp,0,sizeof mp);
for(int i=1;i<=n;++i) e[i].clear(),g[i].clear();
for(int i=1,u,v;i<n;++i) u=read(),v=read(),mp[u][v]=mp[v][u]=1,e[u].push_back(v),e[v].push_back(u);
for(int i=1,u,v;i<n;++i) u=read(),v=read(),g[u].push_back(v),g[v].push_back(u);
for(int i=1;i<=n;++i) ndeg[i]=e[i].size();
for(int i=1;i<=n;++i)
{
int cost=0,u;
memset(vis,0,4*n+4),vis[i]=1,dfs(i,0),memcpy(deg+1,ndeg+1,4*n);
while(1)
{
for(u=1;u<=n;++u) if(!vis[u]&°[u]==1&&vis[fa[u]]) break;
if(u>n) break; else vis[u]=1,++cost;
for(int v:e[u]) --deg[v];
}
for(u=1;u<=n;++u) if(!vis[u]) break;
if(u>n) ans=std::min(ans,cost);
if(e[i].size()>1||u>n||ans<=n) continue;
memset(vis,0,4*n+4),vis[0]=1,memcpy(deg+1,ndeg+1,4*n);
while(1)
{
for(u=1;u<=n;++u) if(!vis[u]&°[u]<=1&&vis[fa[u]]) break;
if(u>n) break; else vis[u]=1;
for(int v:e[u]) --deg[v];
}
for(u=1;u<=n;++u) if(!vis[u]) break;
if(u>n) ans=n;
}
printf("%d\n",ans>n? -1:ans);
}
int main(){for(int T=read();T;--T)work();}