2020牛客暑期多校训练营(第二场)Cover the Tree

题目链接

https://ac.nowcoder.com/acm/contest/5667/C

题目大意

给你一棵树 , 求最少的树链个数使得这棵树的所有节点都被至少一条链经过

输出最少链的个数即方案

解题思路

比赛的时候写了一个假算法卡过了hh

选择一个度数大于1的点为根节点建树 , 然后按照 dfs 序将叶子节点依次加入 vector

记录叶子节点的个数为 cnt = vec.size() , L = (cnt + 1) / 2;

那么需要的最少链的个数为 (cnt + 1) / 2 , 方案为 vec[i] + vec[i + L] , i ∈ [0 , cnt - L) 

证明如下

 

AC_Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 10;
struct Edge{
    int nex , to;
}edge[N << 1];
int head[N] , TOT;
void add_edge(int u , int v)
{
    edge[++ TOT].nex = head[u] ;
    edge[TOT].to = v;
    head[u] = TOT;
}
int du[N] , sa[N] ;
int root , cnt , n;
vector<int>vec;
void dfs(int u , int far)
{
    sa[u] = ++ cnt;
    if(du[u] == 1) vec.push_back(u);
    for(int i = head[u] ; i ; i = edge[i].nex)
    {
        int v = edge[i].to;
        if(v == far) continue ;
        dfs(v , u);
    }
}
signed main()
{
    ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
    cin >> n ;
    for(int i = 1 ; i < n ; i ++)
    {
        int u , v;
        cin >> u >> v;
        add_edge(u , v) , add_edge(v , u);
        du[u] ++ , du[v] ++ ;  
    }
       for(int i = 1 ; i <= n ; i ++) if(du[i] != 1) { root = i ; break ; }
    dfs(root , -1);
    int cnt = vec.size() , f = vec.front() , l = cnt + 1 >> 1;
    cout << l << '\n'; 
    for(int i = 0 ; i + l < cnt ; i ++) cout << vec[i] << " " << vec[i + l] << '\n';
    if(cnt & 1) cout << vec[cnt / 2] << " " << f << '\n';
    return 0;
}
posted @ 2020-07-20 10:37  GsjzTle  阅读(165)  评论(1编辑  收藏  举报