zoukankan      html  css  js  c++  java
  • [CF1042F]Leaf Sets

    题目大意:给定一棵$n$个点的树,将叶子节点分为数个集合,使集合里点对最长距离不超过$k$,求最少集合数。

    题解:贪心,发现将叶子节点分成集合等于把节点划分集合,答案是一样的。因为一定有一个点,到非叶子节点$p$的儿子的距离比到$p$远。然后发现一个集合一定是连续的(或者连续的一定最优),不然不完全可以把中间连起来,且合法。

    $dfs$,如果一个点的最长两个点长度和大于$k$就加一个集合

    注意要用非叶子节点当根,最后答案要加一

    卡点:没用非叶子节点当根

    C++ Code:

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #define maxn 1000010
    int head[maxn], cnt;
    struct Edge {
    	int to, nxt;
    } e[maxn << 1];
    inline void add(int a, int b) {
    	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    }
    int n, k, ans;
    int ind[maxn], fa[maxn], M[maxn];
    void dfs(int u) {
    	if (ind[u] < 2) return ;
    	std::vector<int> E;
    	for (int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if (v != fa[u]) {
    			fa[v] = u;
    			dfs(v);
    			E.push_back(M[v] + 1);
    		}
    	}
    	std::sort(E.begin(), E.end());
    	int now = E.size() - 1;
    	for (; now; now--) if (E[now] + E[now - 1] > k) ans++;
    	else break;
    	M[u] = E[now];
    }
    int main() {
    	scanf("%d%d", &n, &k);
    	int rt = 1;
    	for (int i = 1, a, b; i < n; i++) {
    		scanf("%d%d", &a, &b);
    		add(a, b), add(b, a);
    		ind[a]++, ind[b]++;
    		if (ind[a] != 1) rt = a;
    		if (ind[b] != 1) rt = b;
    	}
    	dfs(rt);
    	printf("%d
    ", ans + 1);
    	return 0;
    }
    

      

  • 相关阅读:
    使用Razor模板构建应用注意的细节
    分享一个秒计数器
    有效提高命中率的缓存设计
    伟大的C语言
    关于在使用Visual C++中使用MMX、SSE指令集的问题
    如何用SVN 或 WINCVS 下载x264 ffdshow T264 Kevinlib
    Visual C++图形特技
    图象处理部分文章列表
    C++,VC资源
    Visual C++ 如何:在各种字符串类型之间进行转换
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9744609.html
Copyright © 2011-2022 走看看