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;
} 
京公网安备 11010502036488号