Description
给定一棵无根树,求它的最小链覆盖,输出方案。
Solution
以任意非叶子结点定根,如果叶子结点个数为奇数则手工在根上再挂一个
对叶子结点按 DFS 序排序,设有 (2s) 个,则 (1 o s+1, 2 o s+2,...),两两匹配即可
多挂的那个结点记得在输出时改成根
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
int dfn[N],n,m,t1,t2,t3;
vector <int> g[N];
int vis[N];
vector <int> leaf;
int d[N],ind;
void dfs(int p)
{
vis[p]=1;
dfn[p]=++ind;
for(int q:g[p])
{
if(!vis[q])
{
dfs(q);
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n;
if(n==1)
{
cout<<"1 1"<<endl;
return 0;
}
if(n==2)
{
cout<<"1 2"<<endl;
return 0;
}
for(int i=1;i<n;i++)
{
cin>>t1>>t2;
g[t1].push_back(t2);
g[t2].push_back(t1);
d[t1]++;
d[t2]++;
}
int sum=0,root;
for(int i=1;i<=n;i++)
{
if(d[i]==1) ++sum, leaf.push_back(i);
else root=i;
}
if(sum&1)
{
++sum;
leaf.push_back(n+1);
g[n+1].push_back(root);
g[root].push_back(n+1);
}
dfs(root);
sort(leaf.begin(),leaf.end(),[](int x,int y){return dfn[x]<dfn[y];});
cout<<sum/2<<endl;
for(int i=0;i<sum/2;i++)
{
cout<<min(n,leaf[i])<<" "<<min(n,leaf[i+sum/2])<<endl;
}
}