牛客周赛
题目链接
https://ac.nowcoder.com/acm/contest/133523/E
经典的构造标准的零分
题目大意就是,给你n个节点,要求这n个节点构成的树的到每个叶子节点的距离是一个m的排列,也就是m级树
题目解析
注意到题目说是树,不是二叉树,假设有要求是m级树,那么就有最小节点数构造方法和最大构造数方法,分别如下:
1.最小方法:

可以知道,最小方法得出,n的最小值至少得是2*m
2.最大方法

可以得到,如果是m级树,那么n最大只能是(m+(m+1))/2+1
int n,m;
cin >> n >> m;
if (m==1) {
if (n!=2) cout <<"NO"<<el;
else {
cout << "YES"<<el;
cout << 1 <<" " << 2 <<el;
}
return;
}
if (n<m*2 || n>(m+1)*m/2+1) cout <<"NO"<<el;
满足条件的构造
else{
cout<<"YES"<<endl;
for(int i=1;i<=m;i++)cout<<i<<" "<<i+1<<endl;
//先构造最长的那条边
cout<<1<<" "<<m+2<<endl;
int now=m+3;//注意,这里已经拿了一个点了,这个是理解这个代码的关键
int lea=n-2*m;//这里就已经把那个m+3那个点给包括进去了
for(int i=m-1;i>=2;i--){
//这个循环的意识,就是构造距离为i的个叶子
int add=min(lea,i-1);//要增加的叶子的节点是i-1和lea(也就是剩余的节点数量),如果i-1大于lea,那就从1开始构造一条有i条边的边,这样到叶子的距离才会是i(就比如5个节点的边到叶子的距离就是4),那么为什么是i-1呢,按道理来说要i个边,加上本来就有的1号根节点,应该是i个节点才对啊,因为本来就已经有了一个节点了,就是上面那个now,去掉这个now,就只差i-1个点了
lea-=add;
int start=i-add;
//这个start也是有道理的,加入要造一个根到叶子距离为i的边,因为有add个节点,按道理来说应该是到i-add+1,不能到i-add,因为如果是在i-add的话,不是只有add-1条边嘛,但是这里这么些
//是因为本来就已经有留一个点了,就是那个now,后面要把这个点连上去
for(int j=0;j<=add;j++){
if(j==0)cout<<start<<" "<<now<<endl;
else cout<<now-1<<" "<<now<<endl;
now++;//这个最后的++也是有道理的,当所有的边都写完了之后再++,就又有一个点了,等价于上面的now
}
}
}

浙公网安备 33010602011771号