题目描述
树形dp
设f[i][j]表示第一棵树中以i为根的子树和第二棵树中以j为根的子树实现对称所需要的最小代价,而i的儿子x和j的儿子y的f[x][y]的值是已经求出来的,如何转移到f[i][j]
二分图带权匹配
我们要求的其实就是个最小权完备匹配(和最大权类似,把边权取反即可),对于儿子数不同的点对,我们可以直接添点,边的权值即为对应点的size。由于费用流不会,果断选择km算法。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=1000+5;
int son1[maxn][maxn],son2[maxn][maxn],n1[maxn],n2[maxn],w[maxn][maxn],a[maxn],b[maxn],sl[maxn],s1[maxn],s2[maxn],w1[maxn][maxn],f[maxn];
int i,n,t1,t2;
bool bz1[maxn],bz2[maxn];
void df1(int x){
int i;
s1[x]=1;
fo(i,1,n1[x]) {
df1(son1[x][i]);
s1[x]+=s1[son1[x][i]];
}
}
void df2(int x){
int i;
s2[x]=1;
fo(i,1,n2[x]) {
df2(son2[x][i]);
s2[x]+=s2[son2[x][i]];
}
}
bool find(int x,int m,int x2){
if (bz1[x]) return 0;
bz1[x]=1;
int i;
fo(i,1,m){
int j=son2[x2][i];
if (bz2[j]) continue;
int p=a[x]+b[j]-w1[x][j];
if (p==0){
bz2[j]=1;
if ((!f[j])||(find(f[j],m,x2))){
f[j]=x;
return 1;
}
}else sl[j]=min(sl[j],p);
}
return 0;
}
void dfs(int x1,int x2){
if ((s1[x1]==0)||(s2[x2]==0)){
w[x1][x2]=s1[x1]+s2[x2];
return;
}
int i,j,m=max(n1[x1],n2[x2]);
if (m==0) {
w[x1][x2]=0;
return;
}
if (n1[x1]<m) {
fo(i,n1[x1]+1,m) if (!son1[x1][i])son1[x1][i]=++t1;
}else fo(i,n2[x2]+1,m) if (!son2[x2][i]) son2[x2][i]=++t2;
fo(i,1,m)
fo(j,1,m) {
dfs(son1[x1][i],son2[x2][j]);
w1[son1[x1][i]][son2[x2][j]]=-w[son1[x1][i]][son2[x2][j]];
}
fo(i,1,m) {
a[son1[x1][i]]=-10000;
f[son2[x2][i]]=0;
fo(j,1,m) a[son1[x1][i]]=max(a[son1[x1][i]],w1[son1[x1][i]][son2[x2][j]]);
}
fo(i,1,m){
fo(j,1,m) sl[son2[x2][j]]=10000;
while (1){
fo(j,1,m) bz1[son1[x1][j]]=0;
fo(j,1,m) bz2[son2[x2][j]]=0;
if (find(son1[x1][i],m,x2)) break;
int d=10000;
fo(j,1,m) if (!bz2[son2[x2][j]]) d=min(d,sl[son2[x2][j]]);
fo(j,1,m) {
if (bz1[son1[x1][j]]) a[son1[x1][j]]-=d;
if (bz2[son2[x2][j]]) b[son2[x2][j]]+=d;else sl[son2[x2][j]]-=d;
}
}
}
w[x1][x2]=0;
fo(i,1,m) w[x1][x2]=w[x1][x2]-w1[f[son2[x2][i]]][son2[x2][i]];
}
int main(){
scanf("%d",&n);t1=n+1;
fo(i,2,n+1){
int x;
scanf("%d",&x);x++;
son1[x][++n1[x]]=i;
}
scanf("%d",&n);t2=n+1;
fo(i,2,n+1){
int x;
scanf("%d",&x);x++;
son2[x][++n2[x]]=i;
}
df1(1),df2(1);
dfs(1,1);
printf("%d\n",w[1][1]);
}