设为首页 加入收藏

TOP

JZOJ 4272. 【NOIP2015模拟10.28B组】序章-弗兰德的秘密
2018-10-21 20:09:49 】 浏览:32
Tags:JZOJ 4272. NOIP2015 模拟 10.28B 序章 兰德 秘密

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。
 
 
 
做法::树型 DP。设状态 F[x][y]表示,第一棵树中 x 节点与第二 棵树中的 y 节点作为根节点匹配的最大同构。例如,上图中所示的 F[x][y] = 3 。 现在转移方程就很显然了: F[x][y] = Max { F[x 的儿子][y 的儿子] } + 1 ; 这里需要枚举 x 的那些儿子与 y 的哪些儿子匹配,这部分时间复 杂度 O( 5! ) ; 最后答案就是 F[1][1]。
 
代码如下:
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #define rep(i,a,b)    for(int i=a;i<=b;i++)
 5 #define N 1007
 6 using namespace std;
 7 int f[N][N], n, m, sn[N][N], sm[N][N], ans, q, p;
 8 bool bj[N];
 9 
10 int max(int a, int b) { if (a > b) return a; return b; }
11 
12 void find(int t, int same)
13 {
14     if (t == sn[q][0] + 1)
15     {
16         f[q][p] = max(f[q][p], same);
17         return;
18     }
19     find(t + 1, same); 
20     bool b = 0;
21     rep(i, 1, sm[p][0]) 
22     {
23         if (bj[i])    continue;
24         b = 1;
25         bj[i] = 1;
26         find(t + 1, same + f[sn[q][t]][sm[p][i]]);
27         bj[i] = 0;
28     }
29     if (!b)
30     {
31         f[q][p] = max(f[q][p], same);
32     }
33 }
34 
35 void work(int x)
36 {
37     if (sn[x][0] == 0)
38     {
39         rep(i, 1, m)
40             f[x][i] = 1;
41         return;        
42     }
43     rep(i, 1, sn[x][0])    work(sn[x][i]);
44     rep(i, 1, m)
45     {
46         if (sm[i][0] == 0)
47         {
48             f[x][i] = 1;
49             continue;
50         }
51         q = x;
52         p = i;
53         find(1, 0);        
54         f[q][p]++;
55         if (x == 1 && i == 1)    ans = max(f[q][p], ans);
56     }
57 }
58 
59 int main()
60 {
61     freopen("frand.in", "r", stdin);
62     freopen("frand.out", "w", stdout);
63     scanf("%d%d", &n, &m);
64     rep(i, 1, n - 1)
65     {
66         scanf("%d%d", &q, &p);
67         sn[q][++sn[q][0]] = p;
68     }
69     rep(i, 1, m - 1)
70     {
71         scanf("%d%d", &q, &p);
72         sm[q][++sm[q][0]] = p;
73     }
74     work(1);
75     printf("%d", ans);
76     fclose(stdin);
77     fclose(stdout);
78     return 0;
79 }

 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++雾中风景10:聊聊左值,纯右值.. 下一篇BZOJ2818: Gcd(莫比乌斯反演)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目