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 }