题面:
大致题意:
给两颗树,然后有一种操作就是修改树的结点编号,现在让两棵树变成相同的,问最少需要修改几次?
分析一波:
先声明下:
- x1 是第一棵树,他的一些子节点 (子树) y11,y12,y13…
- x2 是第二棵树,他的一些子节点 (子树) y21,y22,y23…
1: 两个树必须要同构,才能修改成一样的。
为啥要匹配?
修改的时候,假如在 x1 的子树 和 x2 的子树中,同构的子树,有好几类,然后 每类中,y11 可能变成 y22 要优与变成 y21…总之汇合起来,我们就要得到一个两两成匹配的方案,所以就变成了一个典型的二分图最大权值匹配问题 .
so:权值就是 两个子树的节点变成一致的修改次数。
整棵树的 最少操作数, 就dfs后序,对每颗同深度的子树 进行匹配,最后到达两棵树的根节点
#include<bits/stdc++.h>
#define ks ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define fr first
#define sc second
#define pb push_back
#define pf push_front
#define mp make_pair
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pa;
typedef set<int>::iterator sit;
typedef multiset<int>::iterator msit;
template<class T>inline void read(T &res){
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
void wenjian(){freopen("concatenation.in","r",stdin);freopen("concatenation.out","w",stdout);}
void tempwj(){freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct chongzai{int c; bool operator<(const chongzai &b )const{ return c>b.c; } }sss;
const int maxn=1e3+177;
const int maxm=1e6+177;
const ll mod=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll dp[maxn][maxn];
vector<int >G[3][maxn];
string zxbs[3][maxn];
int dia[maxn];
int n;
int indexx;
struct Node{
int next;
int to;
ll vul;
ll cost;
}edge[maxm];
int head[maxm];
int tot;
void add(int from,int to,ll vul,ll cost){
edge[++tot].next=head[from];
edge[tot].to=to;
edge[tot].vul=vul;
edge[tot].cost=cost;
head[from]=tot;
edge[++tot].next=head[to];
edge[tot].to=from;
edge[tot].vul=0;
edge[tot].cost=-cost;
head[to]=tot;
}
void getzxbs(int x,int f){
vector<string>vt;
zxbs[f][x]+='(';
for(int i=0;i<G[f][x].size();i++){
int v=G[f][x][i];
getzxbs(v,f);
vt.pb(zxbs[f][v]);
}
sort(vt.begin(),vt.end());
for(int i=0;i<vt.size();i++){
zxbs[f][x]+=vt[i];
}
zxbs[f][x]+=')';
}
void init(int nn){
for(int i=0;i<nn+17;i++){
head[i]=0;
}
tot=1;
}
int s,t; // 汇点 源点
ll dis[maxn],incf[maxn];
ll maxflow,ans; //最大流 和 费用
int vis[maxn],pre[maxn];
bool spfa(){
queue<int >qu;
for(int i=0;i<indexx+17;i++){
dis[i]=INF;
vis[i]=0;
}
qu.push(s);
dis[s]=0;
vis[s]=1;
incf[s]=INF;
pre[t]=-1;
while(!qu.empty()){
int x=qu.front();
vis[x]=0;
qu.pop();
for(int i=head[x];i;i=edge[i].next){
if(!edge[i].vul){
continue;
}
int y=edge[i].to;
if(dis[y]>dis[x]+edge[i].cost){
dis[y]=dis[x]+edge[i].cost;
incf[y]=min(incf[x],edge[i].vul);
pre[y]=i;
if(!vis[y]){
vis[y]=1;
qu.push(y);
}
}
}
}
if(pre[t]==-1){
return false;
}
return true;
}
void update(){
int x=t;
while(x!=s){
int i=pre[x];
edge[i].vul-=incf[t];
edge[i^1].vul+=incf[t];
x=edge[i^1].to;
}
maxflow+=incf[t];
ans+=dis[t]*incf[t];
}
ll deal2(){ // 费用流
ans=0;
while(spfa()){
update();
}
return ans;
}
void dfs(int x1,int x2){
// printf("%d -- -- %d \n",x1,x2);
if(G[1][x1].size()==0){
if(x1==x2){
dp[x1][x2]=0;
}else{
dp[x1][x2]=1;
}
// printf("@@ \n");
return ;
}
for(int i=0;i<G[1][x1].size();i++){
int y1=G[1][x1][i];
for(int j=0;j<G[2][x2].size();j++){
int y2=G[2][x2][j];
// printf("%d ****** %d $$ %d %d \n",y1,y2,x1,x2);
if(zxbs[1][y1]==zxbs[2][y2]){
dfs(y1,y2);
}
}
}
indexx=0;
for(int i=0;i<G[1][x1].size();i++){
int y1=G[1][x1][i];
dia[y1]=++indexx;
}
for(int i=0;i<G[2][x2].size();i++){
int y2=G[2][x2][i];
dia[y2+n]=++indexx;
}
s=0,t=++indexx;
init(indexx);
// 建边
for(int i=0;i<G[1][x1].size();i++){
int y1=G[1][x1][i];
for(int j=0;j<G[2][x2].size();j++){
int y2=G[2][x2][j];
if(zxbs[1][y1]==zxbs[2][y2]){
add(dia[y1],dia[y2+n],1,dp[y1][y2]);
}
}
}
for(int i=0;i<G[1][x1].size();i++){
int y1=G[1][x1][i];
add(s,dia[y1],1,0);
}
for(int i=0;i<G[2][x2].size();i++){
int y2=G[2][x2][i];
add(dia[y2+n],t,1,0);
}
dp[x1][x2]=deal2();
if(x1!=x2){
dp[x1][x2]++;
}
// printf("%d &&& %d %lld \n",x1,x2,dp[x1][x2]);
}
int main(){
scanf("%d",&n);
int x;
int root1,root2;
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(x==0){
root1=i;
continue;
}
G[1][x].pb(i);
}
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(x==0){
root2=i;
continue;
}
G[2][x].pb(i);
}
getzxbs(root1,1);
getzxbs(root2,2);
dfs(root1,root2);
printf("%lld\n",dp[root1][root2]);
}
/*
11
10 1 1 5 10 7 4 5 11 0 3
10 1 7 11 10 4 9 5 5 0 1
输出: 5
*/