Gym 101257B:2Trees(DFS+思维)

http://codeforces.com/gym/101257/problem/B

题意:给出两棵叶子数一样的树,在将叶子合并之后,对这个图进行染色,相邻的结点颜色不能相同,问最少需要染的颜色数,并输出合并叶子的方案。

思路:画了好几个图找了下规律,发现对于任意一个这样的图,最多只需要染三种颜色,最少是染两种颜色。

如果合并后的图,每一条从一棵树的根节点走到另一棵树的根节点的路径长度的奇偶性相同,那么这个时候就是只需要染两种颜色。

剩下的情况就是染三种颜色了。

对于每棵树,随便找一个不是叶子结点当做根节点往下DFS(因为无论选择哪个点,弄出来的路径长度奇偶性数量是相同的)求出每棵树路径长度为奇数的个数和为偶数的个数,然后分别记录后就可以求解了。

有两种情况染两种颜色:第一棵树的奇数 = 第二棵树的奇数,第一棵树的奇数 = 第二棵树的偶数。(少考虑了第二种情况,大概以为推论是错的)。然后按要求输出。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 200010
 4 #define INF 0x3f3f3f3f
 5 const double eps = 1e-9;
 6 typedef long long LL;
 7 struct Edge {
 8     int v, nxt;
 9 } edge[N*2];
10 int head[N], tot, col[N], deg1[N], deg2[N], dis1[N], dis2[N], ans, n1, n2;
11 vector<int> leaf1, leaf2, d1, d2, e1, e2;
12 
13 void Add(int u, int v) {
14     edge[tot] = (Edge) {v, head[u]}; head[u] = tot++;
15     edge[tot] = (Edge) {u, head[v]}; head[v] = tot++;
16 }
17 
18 void dfs(int u, int fa, int *dis) {
19     for(int i = head[u]; ~i; i = edge[i].nxt) {
20         int v = edge[i].v;
21         if(v == fa) continue;
22         dis[v] = dis[u] + 1;
23         dfs(v, u, dis);
24     }
25 }
26 //
27 int main() {
28     memset(head, -1, sizeof(head)); tot = 0;
29     scanf("%d", &n1);
30     int rt1 = -1, rt2 = -1;
31     for(int i = 1; i < n1; i++) {
32         int u, v; scanf("%d%d", &u, &v);
33         Add(u, v); deg1[u]++; deg1[v]++;
34     }
35     for(int i = 1; i <= n1; i++)
36         if(deg1[i] == 1) leaf1.push_back(i); // 度为1的点叶子
37         else rt1 = i;
38     dis1[rt1] = 0; // 随便挑一个当根结点然后往下DFS求出距离,因为距离的奇偶是确定的
39     dfs(rt1, -1, dis1);
40 
41 
42     memset(head, -1, sizeof(head)); tot = 0;
43     scanf("%d", &n2);
44     for(int i = 1; i < n2; i++) {
45         int u, v; scanf("%d%d", &u, &v);
46         Add(u, v); deg2[u]++; deg2[v]++;
47     }
48     for(int i = 1; i <= n2; i++)
49         if(deg2[i] == 1) leaf2.push_back(i);
50         else rt2 = i;
51     dis2[rt2] = 0;
52     dfs(rt2, -1, dis2);
53 
54     int odd1, eve1, odd2, eve2;
55     odd1 = eve1 = odd2 = eve2 = 0;
56     int sz = leaf1.size();
57     for(int i = 0; i < sz; i++) { // 求两棵树分别的奇偶距离数
58         if(dis1[leaf1[i]] & 1) odd1++, d1.push_back(leaf1[i]);
59         else eve1++, e1.push_back(leaf1[i]);
60         if(dis2[leaf2[i]] & 1) odd2++, d2.push_back(leaf2[i]);
61         else eve2++, e2.push_back(leaf2[i]);
62     }
63     if(odd1 == odd2) { // 如果第一棵树的奇数距离和第二棵树的奇数(或偶数)距离相等,那么可以只涂两种颜色
64         puts("2");
65         for(int i = 0; i < odd1; i++)
66             printf("%d %d
", d1[i], d2[i]);
67         for(int i = 0; i < eve1; i++)
68             printf("%d %d
", e1[i], e2[i]);
69     } else if(odd1 == eve2) {
70         puts("2");
71         for(int i = 0; i < odd1; i++)
72             printf("%d %d
", d1[i], e2[i]);
73         for(int i = 0; i < eve1; i++)
74             printf("%d %d
", e1[i], d2[i]);
75     } else { // 否则最多只需要三种,可以随便输出
76         int a1 = 0, b1 = 0, a2 = 0, b2 = 0;
77         puts("3");
78         for(int i = 0; i < sz; i++) {
79             if(a1 == odd1) printf("%d ", e1[b1++]);
80             else printf("%d ", d1[a1++]);
81             if(a2 == odd2) printf("%d
", e2[b2++]);
82             else printf("%d
", d2[a2++]);
83         }
84     }
85     return 0;
86 }
原文地址:https://www.cnblogs.com/fightfordream/p/6443806.html