CF 1042 F. Leaf Sets

F. Leaf Sets

http://codeforces.com/contest/1042/problem/F

题意:

  将所有的叶子节点分配到尽量少的集合,一个可行的集合中两两叶子节点的距离<=k。

 

分析:

  可以证明,对于一个子树内的两个叶子节点,把它们分到同一个集合中一定比分到两个集合中好。

  所以一个子树内的叶子集合,能合并,尽量合并。

  从叶子节点dfs,往上推,当到达一个点时,求出这棵子树内所有的叶子集合到这个节点的距离。如果两个距离小于等于k,那么显然是可以合并的。合并后,只返回这棵子树内最小的距离。

  比赛时第33行是这样写的:if(t<k) c.push_back(t); 然后就在第4个测试点wa。。。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #define fi(s) freopen(s,"r",stdin);
12 #define fo(s) freopen(s,"w",stdout);
13 using namespace std;
14 typedef long long LL;
15 
16 inline int read() {
17     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
18     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
19 }
20 
21 const int N = 1000005;
22 
23 vector<int> T[N];
24 int Ans = 0, n, k;
25 int c[N], deg[N];
26 
27 int dfs(int u,int fa) {
28     vector<int> c;
29     for (int i=0; i<T[u].size(); ++i) {
30         int v = T[u][i];
31         if (v == fa) continue;
32         int t = dfs(v, u);
33         c.push_back(t);
34     }
35     int siz = c.size();
36     if (!siz) return 1;
37     
38     sort(c.begin(), c.end());
39     
40     int ans = c[siz - 1];
41     for (int i=1; i<siz; ++i) {
42         if (c[i] + c[i - 1] <= k) Ans --;
43         else {
44             ans = min(ans, c[i - 1]);
45             break; 
46         }
47     }
48     return ans + 1;
49 }
50 
51 int main() {
52     n = read(), k = read();
53     for (int i=1; i<n; ++i) {
54         int u = read(), v = read();
55         T[u].push_back(v), T[v].push_back(u);
56         deg[u] ++, deg[v] ++;
57     }
58     int Root = 0;
59     for (int i=1; i<=n; ++i) {
60         if (deg[i] == 1) Ans ++;
61         if (deg[i] > 1 && !Root) Root = i;
62     }
63     dfs(Root, 0);
64     cout << Ans;
65     return 0;
66 }

 

posted @ 2018-09-17 20:52  MJT12044  阅读(214)  评论(0编辑  收藏  举报