Codeforces Global Round 16 题解
Posted 风去幽墨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Global Round 16 题解相关的知识,希望对你有一定的参考价值。
E. Buds Re-hanging
题意:
给出一棵多叉树,定义一种节点称之为“树芽”。其条件为:
- 不是根节点
- 至少含有一个子节点
- 所有的子节点都为叶子节点。
现在可以进行一种操作:将”树芽“节点及其所有子节点嫁接到其他节点上。
问:如果可以进行任意次上述操作时,树上最终保留的叶子节点最小个数是多少?
题解:
首先,明确一点:
当一次嫁接后,如果产生一个新的“树芽”节点,那么新产生的“树芽”节点也可以进行嫁接操作。
思路:
如果期望最终叶子节点最少。那么将有效的方式是将“树芽”节点嫁接到一个叶子节点上,这样会使叶子节点个数减一。
那么如何计算所有的“树芽”节点呢?以及如何计算由于嫁接操作可能产生的新的“树芽”节点呢?
可以尝试模拟一下嫁接操作,不难发现,当一个节点的所有子节点中有一个或多个叶子节点时,该节点就可能成为一个“树芽”节点。当一个节点的所有子节点不存在一个叶子节点的时候,该节点会因为嫁接操作变成一个叶子节点。
有上述两条规则时,就很容易找到“树芽”节点与叶子节点了。
由于可以进行任意次操作,且所有操作均可逆转。所以无论树的状态是什么样子的,最终都可以达到同一种最优态。
那么不妨假设吧所有的“树芽”节点先嫁接到根节点上去。此时存在的叶子节点个数为N-k-1 (节点个数-“树芽”节点个数-根节点)。之后再将“树芽”节点依次嫁接到其他叶子节点上就可以使最终叶子节点个数最小。
此时有两种情况:
(1)根节点的子节点有一个叶子节点,那么所有的“树芽”节点都可以依次嫁接到该叶子节点(或其因嫁接操作产生的新的叶子节点上),那么所有的“树芽”节点都可以有效的嫁接,即使叶子节点个数减一。所有答案为N-k-1-k = N -2k-1。
(2)根节点的子节点没有叶子节点,那么只能耗费一个“树芽”节点来作为嫁接的起始,即会有一个“树芽”节点会进行无效的嫁接。所以答案为N-k-1-(k-1) = N - 2k。
代码:
#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 题解的主要内容,如果未能解决你的问题,请参考以下文章