JZOJ7月24日提高组T1 序章-弗兰德的秘密

JZOJ7月24日提高组T1 序章-弗兰德的秘密

题目

背景介绍
弗兰德,我不知道这个地方对我意味着什么。这里是一切开始的地方。3年前,还是个什么都没见过的少年,来到弗兰德的树下,走进了封闭的密室,扭动的封尘已久机关,在石板上知道了这个世界最角落的最阴暗的东西。那种事情,从未忘怀,从未动摇,我还记得,那一天,我,里修,第一次拔起了剑……
弗兰德的密室里,机关上方画着两棵树的字样,机关下方是一个有数字的刻度……
弗兰德最高的两棵树,只要知道两棵树的共同的相似度就行了……
给定两棵有根树,可以任意删除两棵树上的节点(删除一棵节点必须保证该节点的子树内的所有节点也必须要被删除,换一种说法,删除后的树必须联通并形成一棵树,且根节点不能被删除),使得删除后的两棵树同构,这两棵树有一个共同大小,即树的size,最大化同构的树的size即为机关的答案……
注:两棵同构的树要满足以下条件:
1、两棵树节点个数相等。
2、两棵树的以根节点的儿子为根子树对应同构。如下图,为两棵同构的有根树。
如下图,为两棵同构的有根树。
在这里插入图片描述

题解

题意

给出两个有根树,求出最大的同构的树的节点个数
同构定义:
1、两棵树节点个数相等。
2、两棵树的以根节点的儿子为根子树对应同构。
照搬题目QAQ

分析

很明显是一个树形DP
看到数据

1 ≤ n ≤ 1000

可以想到用 O ( n 2 ) O(n^2) 来求
f [ i ] [ j ] f[i][j] 表示第1棵树到了第 i i 个点,第2棵树到了第 j j 个点的最大相似度(即节点个数)
注意到数据还有一点就是

数据保证两棵树上每个节点的度均不超过5

出题人好良心
那么对于当前这个 f [ i ] [ j ] f[i][j] ,可以思考暴力转移
暴力将第1棵树中 i i 的儿子和第2棵树中 j j 的儿子连接起来,时间复杂度是 O ( 5 ! ) O(5!)
那么 f [ i ] [ j ] f[i][j] 就等于 m a x ( f [ i ] [ j ] ) + 1 max(f[i的儿子][j的儿子])+1
总的时间复杂度是 O ( 5 ! n 2 ) O(5!*n^2)

Code

#include<cstdio>
#include<iostream>
using namespace std;
int n,m,i,x,y,one,two,ans,tree1[1005][10],tree2[1005][10],f[1005][1005];
bool b[1005];
void dg2(int now,int sum)
{
	int i;
	bool bj;
	if (now>tree1[one][0])
	{
		f[one][two]=max(f[one][two],sum);
		return;
	}
	dg2(now+1,sum);
	bj=false;
	for (i=1;i<=tree2[two][0];i++)
	{
		if (b[i]==true) continue;
		bj=true;
		b[i]=true;
		dg2(now+1,sum+f[tree1[one][now]][tree2[two][i]]);
		b[i]=false;
	}
	if (bj==false) f[one][two]=max(f[one][two],sum);
}
void dg1(int now)
{
	int i;
	if (tree1[now][0]==0)
	{
		for (i=1;i<=m;i++)
			f[now][i]=1;
		return;
	}
	for (i=1;i<=tree1[now][0];i++)
		dg1(tree1[now][i]);
	for (i=1;i<=m;i++)
	{
		if (tree2[i][0]==0)
		{
			f[now][i]=1;
			continue;
		}
		one=now;
		two=i;
		dg2(1,0);
		f[now][i]++;
		if (now==1&&i==1) ans=max(ans,f[now][i]);
	}
}
int main()
{
	freopen("frand.in","r",stdin);
	freopen("frand.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		tree1[x][0]++;
		tree1[x][tree1[x][0]]=y;
	}
	for (i=1;i<m;i++)
	{
		scanf("%d%d",&x,&y);
		tree2[x][0]++;
		tree2[x][tree2[x][0]]=y;
	}
	dg1(1);
	printf("%d\n",ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/LZX_lzx/article/details/107562708