比赛的时候 少考虑一种情况 。。还是欠考虑了这种题
如果有直链的话 把多于1个的直链 连到 这个直链上就行
有分支的话 那么把这个分支 的末端连向 这个直链的末端 即可
所以我们只需要返回一个末端值就可以了
如果返回的末端值是 -1 就定义他为一个有分支的分支 那么我们直接将这个分支的左末端连向直链
右末端可以作为新直链的末端
还有如果分支里面有 > 3个的分支话 必须把 一个分支 直接断开 连向直链
然后再把这个剩下的两个分支 连到新的直链里面去
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<utility>
using namespace std;
const int N = 2e5 + 10;
struct node{
int a,b,c,d;
};
int head[N],to[N],last[N],cnt;
void add(int a,int b){
to[++cnt] = b;
last[cnt] = head[a];
head[a] = cnt;
}
int d[N];
int sum = 0,root;
int out1[N],out2[N],out3[N],out4[N];
queue<node>q;
int dfs(int x,int lastt){
int ans = 0,mo = x;
for(int i = head[x]; i != -1; i = last[i]){
int j = to[i];
if(j == lastt) continue; //如果是分支的分支
int s = dfs(j,x);
//cout << x << " " <<j << " " << s << endl;
if(s < 0) continue;
++ans;
if(ans == 1) mo = s;
else if(ans == 2){
q.push({lastt,x,mo,s}); //如果有两个直链分支 mo就是第一个支的末节点 s即为第二个支的末节点
mo = -1;
}else{
q.push({x,j,j,s}); //若大于三 必须把这个拆开另外连接
}
}
return mo;
}
int main(){
int t;
cin >> t;
memset(head,-1,sizeof head);
while(t--){
int n;
sum = 0;
cnt = 0;
cin >> n;
for(int i = 1; i <= n - 1; i++){
int x,y;scanf("%d%d",&x,&y);
d[y]++;
d[x]++;
add(x,y);
add(y,x);
}
for(int i = 1;; i++){
if(d[i] == 1){
root = i;
break;
}
}
dfs(root,-1);
while(q.size()){
node p = q.front();
q.pop();
out1[++sum] = p.a;
out2[sum] = p.b;
out3[sum] = root; //最一开始的root 就是可以看成一个链的最末端 然后每次更新root为新链的末端即可
out4[sum] = p.c;
root = p.d;
}
cout << sum << endl;
for(int i = 1; i <= sum; i++){
printf("%d %d %d %d\n",out1[i],out2[i],out3[i],out4[i]);
}
for(int i = 1; i <= n; i++){
head[i] = -1;
d[i] = 0;
}
}
return 0;
}