[USACO23OPEN] Tree Merging G 题解
前言
赛时只打出了特殊性质,还是太菜了 /kk。
解法
以下描述中,“原始状态”指的是未进行任何合并操作的树,“目标状态”指的是“进行完所有合并操作后的树”,
令
-
目标状态包含节点
b ; -
-
计算出
最后构造方案时,从根节点开始按照深度递增一直算到叶子节点,枚举每一个深度指定的节点
放代码:
/*
ID: CrowMatrix
TASK: Tree Merging
LANG: C++
*/
#include<bits/stdc++.h>
using namespace std;
int p1[1001],p2[1001],d[1001],w[1001];
bool e[1001],c[1001][1001];
int main(){
ios::sync_with_stdio(false);
int t; cin>>t;
while(t--){
int n,r; cin>>n;
for(int i=1;i<=n;i++)p1[i]=p2[i]=e[i]=w[i]=d[i]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)c[i][j]=false;
for(int i=1;i<n;i++){
int v,p; cin>>v>>p; p1[v]=p;
} // 原状态
for(int i=1;i<=n;i++)if(!p1[i])r=i;
int m; cin>>m; e[r]=true;
for(int i=1;i<m;i++){
int v,p; cin>>v>>p; p2[v]=p,e[v]=true;
} // 目标状态
for(int i=n;i;i--)
for(int j=1;j<=n;j++)
if(j!=r)d[j]=d[p1[j]]+1; // 计算节点深度
for(int i=n;i;i--)
for(int j=1;j<=n;j++)
if(d[j]==i)
if(e[j])c[j][j]=true;
else for(int k=j;k<=n;k++)
if(e[k])for(int l=c[j][k]=1;l<=n;l++)
if(p1[l]==j){
bool f=false;
for(int p=1;p<=n;p++)
f|=p2[p]==k&&c[l][p];
c[j][k]&=f; // 逐一检查各项条件是否满足
}
cout<<n-m<<endl; w[r]=r;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(d[j]==i){
for(int k=1;k<=n;k++)
if(p2[k]==w[p1[j]]&&c[j][k])w[j]=k; // 找合并的目标
if(j!=w[j])cout<<j<<' '<<w[j]<<endl;
}
}
return 0;
}