2020.7.24 T1序章-弗兰德的秘密 (jz暑假训练day9)

Description

背景介绍
弗兰德,我不知道这个地方对我意味着什么。这里是一切开始的地方。3年前,还是个什么都没见过的少年,来到弗兰德的树下,走进了封闭的密室,扭动的封尘已久机关,在石板上知道了这个世界最角落的最阴暗的东西。那种事情,从未忘怀,从未动摇,我还记得,那一天,我,里修,第一次拔起了剑……

弗兰德的密室里,机关上方画着两棵树的字样,机关下方是一个有数字的刻度……
弗兰德最高的两棵树,只要知道两棵树的共同的相似度就行了……
给定两棵有根树,可以任意删除两棵树上的节点(删除一棵节点必须保证该节点的子树内的所有节点也必须要被删除,换一种说法,删除后的树必须联通并形成一棵树,且根节点不能被删除),使得删除后的两棵树同构,这两棵树有一个共同大小,即树的size,最大化同构的树的size即为机关的答案……

注:两棵同构的树要满足以下条件:
1、两棵树节点个数相等。
2、两棵树的以根节点的儿子为根子树对应同构。如下图,为两棵同构的有根树。
如下图,为两棵同构的有根树。

在这里插入图片描述

Input

一行两个整数n,m分别表示两棵有根树的大小。
以下n-1行描述第一棵树,每行两个数x,y表示x号节点是y号节点父亲。
以下m-1行描述第二棵树,每行两个数x,y表示x号节点是y号节点父亲。
数据保证两棵树的1号节点均为根。

Output

一行一个数,表示两棵树的相似度(删除后最大化的同构树的大小)。

Sample Input

3 3
1 2
1 3
1 2
2 3

Sample Output

2
【样例解释】
第一棵树可以保留1号节点和2号节点删除3号节点,也可以保留1号节点与3号节点删除2号节点,
第二棵树保留1号节点和2号节点删除3号节点。
剩下的树同构,树的节点个数均为2。

Data Constraint

对于30%的数据,1 ≤ n ≤10
对于60%的数据,1 ≤ n ≤ 100
对于100%的数据,1 ≤ n ≤ 1000数据保证两棵树上每个节点的度均不超过5。

今天是中二的一天

正解

设f[x][y]表示第一颗树的x节点与第二棵树的y节点的相似度,假如x与y都只有1个儿子,可以发现f[x][y]=1加上这两个节点的儿子的相似度(f[sonx][sony]),那么若有一个以上的儿子,我们要选择两两匹配儿子的相似度,使儿子相似度总和最大化。而题目要求一个点的度最多5,说明根节点最多5个儿子,其他节点最多4个儿子,所以可以直接阶乘找匹配。

#include<cstdio>
#include<iostream>
#define N 1007
using namespace std;
int n,m,ans,f[N][N],d[N][2],son1[N][50],son2[N][50];
bool bz1[N],bz2[N];
void dg(int x,int y,int num,int now){
	if(now>num){
		int res=0;
		for(int i=1;i<=num;i++)
			res+=f[d[i][0]][d[i][1]];
		ans=max(ans,res);
	}else{
		for(int i=1;i<=son1[x][0];i++){
			if(bz1[son1[x][i]]) continue;
			bz1[son1[x][i]]=true;
			for(int j=1;j<=son2[y][0];j++){
				if(bz2[son2[y][j]]) continue;
				d[now][0]=son1[x][i];
				d[now][1]=son2[y][j];
				bz2[son2[y][j]]=true;
				dg(x,y,num,now+1);
				bz2[son2[y][j]]=false;
			}
			bz1[son1[x][i]]=false;
		}
	}
}
void dfs(int x,int y){
	f[x][y]=1;
	for(int i=1;i<=son1[x][0];i++){
		for(int j=1;j<=son2[y][0];j++){
			int s1=son1[x][i],s2=son2[y][j];
			dfs(s1,s2);
		}
	}
	ans=0;
	dg(x,y,min(son1[x][0],son2[y][0]),1);//递归暴力找匹配
	f[x][y]+=ans;
}
int main(){
	freopen("frand.in","r",stdin);
	freopen("frand.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		son1[x][++son1[x][0]]=y;//认为这题还是邻接表好一点,但是说真的打起来没有链式前向星香
	}
	for(int i=1;i<m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		son2[x][++son2[x][0]]=y;
	}
	dfs(1,1);
	printf("%d",f[1][1]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值