• Codeforces 1566E Buds Re-hanging


    原题链接 Codeforces Global Round 16 E. Buds Re-hanging

    首先想到,如果我们把一个(buds)挂到一个叶子上,那么会使得叶子总数减(1)
    还有就是如果我们可以把这个树搞成一条链,那么总叶子数一定是最少的,就是让树“越瘦越好”。

    如果原来一个(buds)挂在一个没有其他孩子的结点上,我们拿走这个(buds)之后会使得总叶子数加(1),我们称这个结点为 (alpha),如果一个buds挂在一个有其他孩子的节点上,那么拿走这个(buds)总叶子数不会改变,我们称这个结点为(eta)

    我们考虑把所有的(buds)全挂在(root)上,那么这样做会使结果变坏吗?当然不会

    1. 如果一个(buds)挂在一个(eta)结点上,那么拿走后总叶子数不变。
    2. 如果一个(buds)挂在一个(alpha)结点上,那么拿走后总叶子数会加(1),但是我们完全可以再搞一个(buds)挂在(alpha)结点上,这样就叶子总数又减少了。

    全挂在(root)上之后,我们考虑再将其变成一条链子,怎么变呢?

    首先设总结点数为(n)(buds)数为(k),那么由于所有(buds)全挂在了(root)上,那么现在的叶子数就是(n - k - 1)
    情况一:如果(root)上有一个叶子结点, 那么我们不妨把(k)(buds)依次全挂到这个叶子节点上,那么我们挂一次少一个叶子,那么答案就是(n - k - 1 - k)
    情况二:如果(root)上没有叶子结点,那么我们就把(k - 1)(buds)都依次挂到一个(bud)上就行,那么答案就是(n - k - 1 - (k - 1))

    代码:

    // Problem: E. Buds Re-hanging
    // Contest: Codeforces - Codeforces Global Round 16
    // URL: https://codeforces.com/contest/1566/problem/E
    // Memory Limit: 256 MB
    // Time Limit: 1000 ms
    // 
    // Powered by CP Editor (https://cpeditor.org)
    
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 2E5 + 10;
    vector<int> g[N];
    int type[N]; //0 -- root, 1 -- leaf, 2 -- bud
    
    void dfs(int u, int fa) {
    	bool leaf = false;
    	for (auto v : g[u]) {
    		if (v == fa) continue;
    		dfs(v, u);
    		if (type[v] == 1) leaf = true;
    	}
    	
    	if (u != fa) {
    		if (!leaf) type[u] = 1;
    		else type[u] = 2;
    	}
    }
    
    int main() {
    	int _; scanf("%d", &_);
    	while (_--) {
    		int n;
    		scanf("%d", &n);
    		for (int i = 1; i <= n; i++) g[i].clear();
    		memset(type, -1, sizeof type);
    		
    		for (int i = 1; i <= n - 1; i++) {
    			int u, v;
    			scanf("%d%d", &u, &v);
    			g[u].push_back(v);
    			g[v].push_back(u);
    		}
    		
    		type[1] = 0;
    		dfs(1, 1);
    		
    		bool rHas_leaf = false;
    		for (auto it: g[1]) {
    			if (type[it] == 1) {
    				rHas_leaf = true;
    				break;	
    			}
    		}
    		
    		//将所有buds直接接到根上,这样在把buds拿走接到一个leaf上只会减少一个leaf数,而不会增加leaf
    		//设buds有k个,那么现在叶子节点数n - k - 1
    		/*
    		如果根有叶子结点,我们选择将k个buds顺次接到这个叶子结点上,接一次减少1,所以答案n - k - 1 - k
    		如果根没有叶子结点,那么将其他buds接到其中一个bud上去,那么答案n - k - 1 - (k - 1)
    		*/		
    		int k = 0;
    		for (int i = 1; i <= n; i++) {
    			if (type[i] == 2) k += 1;
    		}
    		
    		if (rHas_leaf) printf("%d
    ", n - 2 * k  - 1);
    		else printf("%d
    ", n - 2 * k);
    	}
    	
        return 0;
    }
    
  • 相关阅读:
    vue教程1-07 模板和过滤器
    vue教程1-06 v-bind属性、class和style
    vue教程1-05 事件 简写、事件对象、冒泡、默认行为、键盘事件
    Webstorm使用教程详解
    diff, cmp, patch
    grep, sed, awk
    which,whereis, locate, find
    tar, rar, unrar, zip, unzip
    groups, usermod, chown, chgrp, chmod
    pwd, cd, ls, touch, mkdir, rmdir, rm
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/15292926.html
Copyright © 2020-2023  润新知