2020牛客暑期多校訓練營(第二場)C - Cover the Tree - DFS序,構造
阿新 • • 發佈:2020-07-16
Description
給定一棵無根樹,求它的最小鏈覆蓋,輸出方案。
Solution
以任意非葉子結點定根,如果葉子結點個數為奇數則手工在根上再掛一個
對葉子結點按 DFS 序排序,設有 \(2s\) 個,則 \(1 \to s+1, 2\to 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; } }