题意:要求输出一棵树的形态(即树的边),要求:总共有n个点,其中k个叶子节点(度为1),并且这棵树的直径要最小。
题解:考虑一棵树,先画出一条直径,现在假设这个直径是最小的,那么现在考虑如何向直径链上加入树的所有节点,且不使得树的直径变大,学过均值的同学都知道要找到直径的中点,然后向外延伸一条链(树枝),否则,如果更偏左边一些,那么直径的右链和新加入的链的直径会超过原有直径。而我们又想让一条链可以消耗尽可能少的叶子数量,并且带有尽可能多的节点,那么显然就是没有枝杈的赤裸裸的链最节省叶子节点数。那么现在这棵树的形态一定是:一个根节点,向外辐射出若干条赤裸的链。再来考虑致敬最小这个条件,我们希望每条链平摊最少的节点,那么就平均分就可以了,最后多的几个就分到不同的链上一条链一个就好了。说了半天…………其实就是找一个根节点,然后向外长k个链,转着圈加节点就行了。。
Code:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
int length[MAXN];
int n,k;
int main(){
cin>>n>>k;
n--;
int delta = n%k;
int length = n/k;
int now =1;
if (delta>=2){
cout<<2*(length+1)<<endl;
}else if (delta==1){
cout<<2*length+1<<endl;
}else{
cout<<2*length<<endl;
}
for (int i=0;i<delta;i++){
now++;
cout<<"1 "<<now<<endl;
for (int j=1;j<length+1;j++){
now++;
cout<<now<<" "<<now-1<<endl;
}
}
for (int i=0;i<k-delta;i++){
now++;
cout<<"1 "<<now<<endl;
for (int j=1;j<length;j++){
now++;
cout<<now<<" "<<now-1<<endl;
}
}
return 0;
}