标程写法:
n<=2时,显然==s/2(s为叶子结点数)

s>=3时,将结点按照dfs序排序,l1,l2,l3...假设s为偶数;

那么对于l1->ls/2+1, l2-> ls/2+2...

假设这条链上的儿子结点所覆盖的区间【l,r】,

如果 r < = s/2 ,那么这条边会被 lr - lr + s/2 覆盖

如果 l > s/2 ,那么这条边会被 lL-s/2 - lL;

否则,根的度数不为1,所以 l ≠ 1或者 r ≠ s 必有一个是满足的;l ≠ 1可以得出,这条边在l 1- l s/2+1; r ≠ s,这条边被 l s/2- ls 覆盖;

s点为奇数时,只需根据叶子结点再接一个节点。。。

我觉得,根据做题经验吧;
我们队写的当时也是这个想法,当然不可能有这么严谨的证明;连蒙带猜吧。。。

#include<bits/stdc++.h>
using namespace std;
const int maxn=210000;
int head[maxn],n,cnt,s=0,tot=0,leaf[maxn],du[maxn];
struct edge{
    int nx,to;
}edge[maxn*2];
void add(int u,int v)
{
    edge[++cnt].nx=head[u];
    edge[cnt].to=v;
    head[u]=cnt;
}
void dfs(int u,int fa)
{
    if(du[u]==1){
        leaf[++tot]=u;
    }
    for(int i=head[u];i;i=edge[i].nx)
    {
        int v=edge[i].to;
        if(v!=fa){
            dfs(v,u);
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
        du[u]++,du[v]++;//判断度数,度数为1,则为叶子结点
    }
    int rt=0;
    for(int i=1;i<=n;i++)
        if(du[i]>1) rt=i;//确定根,根据标程的证明,n>3的情况下,根的度数不能为1
    dfs(rt,0);
    int k=0;
    printf("%d\n",(tot+1)/2);
    for(int i=1;2*i<=tot;i++)
    {
        printf("%d %d\n",leaf[i],leaf[i+(tot+1)/2]);//跟据上面的证明,li -li+s/2+1
    }
    if(tot&1) printf("%d %d\n",rt,leaf[(tot+1)/2]);
}