1 7 1 4 6 5 6 3 1 2 1 6 1 7
思路:先以为根画出上面的图。
节点度为,有两个度为的叶子节点,我们可以知道,如果将边断开,然后再将其中的一个叶子和树上度为的叶子相连(比如连),此时是最优的,因为这样不必在断开后还需要断开的一个叶子。
所以我们的策略是:如果某个点只有一条链,不操作;如果有两条链(两个叶子节点),就和上面一样操作,如果有多于两条,任意连即可(随便和其它叶子节点连接)。
MyCode:
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn=1e5+7,maxm=2e5+7; int n,head[maxn],to[maxm],Next[maxm],tot; inline void add(int x,int y) { to[++tot]=y; Next[tot]=head[x]; head[x]=tot; to[++tot]=x; Next[tot]=head[y]; head[y]=tot; } int root; vector<pair<int,int> >v; int dfs(int x,int f) { int m(0),m1(0),m2(0),cnt(0); for(int i=head[x],y=to[i];i;i=Next[i],y=to[i]) { if(y==f) continue; m=dfs(y,x);//子树中叶子节点的编号 if(m) { cnt+=1;//叶子节点的数量 if(cnt==1) m1=m;//记录第一个叶子 else if(cnt==2) m2=m;//记录第二个叶子 else { v.emplace_back(make_pair(x,y)); //断开x、y v.emplace_back(make_pair(m,root)); //连接根和y的叶子节点 root=y; //y成为新的根 } } } if(!cnt) return x; //叶子节点 else if(cnt==1) return m1;//一条链 else {//x有两条链 v.emplace_back(make_pair(x,f)); //断开x、父节点 x此时的度为2 v.emplace_back(make_pair(m1,root)); //连接根和x的其中一个叶子节点 root=m2; //x的另外一个叶子节点成为根 return 0; } } inline void solve() { cin>>n; v.clear(); tot=0; memset(head,0,(n+1)<<2); for(int i=1,x,y;i<n;++i) { cin>>x>>y; add(x,y); } for(int i=1;i<=n;++i) if(!Next[head[i]]) { root=i; break; } dfs(root,0);//度为一的点为根,便于连边(拆掉后的长链直接和度为1的根连接) int m=v.size(); cout<<m/2<<'\n'; for(int i=0;i<m;i+=2) { cout<<v[i].first<<' '<<v[i].second<<' '<<v[i+1].first<<' '<<v[i+1].second<<'\n'; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int _; cin>>_; while(_--) solve(); return 0; }