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; }
凡所不能将我击倒的,都将使我更加强大