编程之美2015测试赛 题目1 : 同构
题目链接:http://hihocoder.com/contest/msbop2015warmup/problem/1
给定2个树A和B,保证A的节点个数>=B的节点个数。
现在你需要对树A的边进行二染色。
一个好的染色方案,指不存在一个树A中的连通块,同时满足以下2个条件
1. 其中只有同色的边
2. 和B同构。两个树同构是指,存在一个一一映射(既是单射又是满射),将树B的各节点映射到不同的树A的节点,使得原来在树B中相邻的点,在映射后,仍相邻。
问是否存在一种好的染色方案。
输入
第一行一个整数T (1<=T<=10),表示数据组数。
接下来是T组输入数据,测试数据之间没有空行。
每组数据格式如下:
第一行一个整数N ,表示树A的节点总数。
接下来N-1行,每行2个数a, b (1 <= a, b <= N)表示树A的节点a和b之间有一条边。
接下来一行,一个整数M(1 <= M <= N),表示树B的节点总数。
接下来M-1行,每行2个数a, b (1 <= a, b <= M)表示树B的节点a和b之间有一条边。
输出
对每组数据,先输出“Case x: ”,x表示是第几组数据,然后接“YES”/“NO”,表示是否存在所求的染色方案。
算法分析:这是一道好题呀。首先,如果树A的深度超过1的话,我们可以对树A进行交叉染色,这样就避免了同时满足以上那两个条件了;那么如果树A和树B深度都是1的时候呢(即一个根节点连着n-1个叶节点),这时候如果树B的叶节点个数小于等于(树A的叶节点个数+1)/2,就一定存在树A和树B同构且所有边同色的情况。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #define inf 0x7fffffff 8 using namespace std; 9 const int maxn=1000000+10; 10 11 int n,m; 12 int du1[maxn],du2[maxn],cnt1,cnt2; 13 14 int main() 15 { 16 int t,ncase=1; 17 scanf("%d",&t); 18 while (t--) 19 { 20 scanf("%d",&n); 21 memset(du1,0,sizeof(du1)); 22 memset(du2,0,sizeof(du2)); 23 int maxdu1=-1,maxdu2=-1; 24 int a,b; 25 cnt1=cnt2=0; 26 for (int i=1 ;i<n ;i++) 27 { 28 scanf("%d%d",&a,&b); 29 du1[a]++; 30 du1[b]++; 31 } 32 scanf("%d",&m); 33 for (int i=1 ;i<m ;i++) 34 { 35 scanf("%d%d",&a,&b); 36 du2[a]++; 37 du2[b]++; 38 } 39 for (int i=1 ;i<=n ;i++) 40 { 41 if (du1[i]>maxdu1) maxdu1=du1[i]; 42 } 43 for (int i=1 ;i<=m ;i++) 44 { 45 if (du2[i]>maxdu2) maxdu2=du2[i]; 46 if (du2[i]==1) cnt2++; 47 } 48 if (maxdu2==1) cnt2--; 49 if (maxdu2<=(maxdu1+1)/2 && cnt2==m-1 && maxdu2==m-1) 50 printf("Case %d: NO\n",ncase++); 51 else printf("Case %d: YES\n",ncase++); 52 } 53 return 0; 54 }