Codeforces Global Round 16 题解

Posted 风去幽墨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Global Round 16 题解相关的知识,希望对你有一定的参考价值。

E. Buds Re-hanging

题意:

给出一棵多叉树,定义一种节点称之为“树芽”。其条件为:

  1. 不是根节点
  2. 至少含有一个子节点
  3. 所有的子节点都为叶子节点。

现在可以进行一种操作:将”树芽“节点及其所有子节点嫁接到其他节点上。

问:如果可以进行任意次上述操作时,树上最终保留的叶子节点最小个数是多少?

题解:

首先,明确一点:
当一次嫁接后,如果产生一个新的“树芽”节点,那么新产生的“树芽”节点也可以进行嫁接操作。

思路:
如果期望最终叶子节点最少。那么将有效的方式是将“树芽”节点嫁接到一个叶子节点上,这样会使叶子节点个数减一。
那么如何计算所有的“树芽”节点呢?以及如何计算由于嫁接操作可能产生的新的“树芽”节点呢?
可以尝试模拟一下嫁接操作,不难发现,当一个节点的所有子节点中有一个或多个叶子节点时,该节点就可能成为一个“树芽”节点。当一个节点的所有子节点不存在一个叶子节点的时候,该节点会因为嫁接操作变成一个叶子节点。
有上述两条规则时,就很容易找到“树芽”节点与叶子节点了。
由于可以进行任意次操作,且所有操作均可逆转。所以无论树的状态是什么样子的,最终都可以达到同一种最优态。
那么不妨假设吧所有的“树芽”节点先嫁接到根节点上去。此时存在的叶子节点个数为N-k-1 (节点个数-“树芽”节点个数-根节点)。之后再将“树芽”节点依次嫁接到其他叶子节点上就可以使最终叶子节点个数最小。
此时有两种情况:
(1)根节点的子节点有一个叶子节点,那么所有的“树芽”节点都可以依次嫁接到该叶子节点(或其因嫁接操作产生的新的叶子节点上),那么所有的“树芽”节点都可以有效的嫁接,即使叶子节点个数减一。所有答案为N-k-1-k = N -2k-1。
(2)根节点的子节点没有叶子节点,那么只能耗费一个“树芽”节点来作为嫁接的起始,即会有一个“树芽”节点会进行无效的嫁接。所以答案为N-k-1-(k-1) = N - 2
k。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pii pair<int,int>
#define io_init  ios::sync_with_stdio(false);    \\
            cin.tie(0);                     \\
            cout.tie(0);
const int maxn = 2e5+5;
const int mod = 998244353;
int t;
int n,m,k;
vector<int> vec[maxn],tmp[maxn],type;
bool vis[maxn];
unordered_set<int> buds;
int budsnum,numl;

//建树
void build(int rt)
{
    vis[rt]=true;
    for(int i=0;i<tmp[rt].size();++i)
    {
        int nxt = tmp[rt][i];
        if(!vis[nxt])
        {
            vec[rt].push_back(nxt);
            build(nxt);
        }
    }
}
//找“树芽”节点与叶子节点
void findbuds(int rt)
{
    bool leaves = false;
    for (int i=0;i<vec[rt].size();++i) {
        int nxt =vec[rt][i];
        findbuds(nxt);
        if (type[nxt] == 1) leaves = true;
    }
    if (!leaves) type[rt] = 1;
    else type[rt] = 2;
}

int main()
{
    io_init;
    cin>>t;
    while(t--)
    {   
        cin>>n;
        // clear
        for(int i=0;i<=n;++i)
        {
            vis[i]=false;
            vec[i]=vector<int>();
            tmp[i]=vector<int>();
        }
        type.assign(n+1, -1);
        budsnum=0;
        for(int i=0;i<n-1;++i)
        {
            int u,v;
            cin>>u>>v;
            tmp[u].push_back(v);
            tmp[v].push_back(u);
        }
        build(1);
        findbuds(1);
        type[1]=0;
        int root_leaf = 0;
        for(int i=0;i<vec[1].size();++i)
        {
            int nxt = vec[1][i];
            if(type[nxt]==1)
                root_leaf=1;
        }
        for(int i=1;i<=n;++i)
        {
            budsnum+=(type[i]==2);
        }
        cout<<n-2*budsnum-root_leaf<<"\\n";
    }
    return 0;
}

后续题目,若有时间会继续补。

欢迎指正与评论!

以上是关于Codeforces Global Round 16 题解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Global Round 1

Codeforces Global Round 1

Codeforces Global Round 1

Codeforces Global Round 1

Codeforces Global Round 19

Codeforces Global Round 1 AParity