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;
}