题目链接:G. New Roads
题意:给出n个结点,t层深度,每层有a[i]个结点,总共有k个叶子结点,构造一棵树。
分析:
考虑一颗树,如果满足每层深度上有a[i]结点,最多能有多少叶子结点
那么答案很简单,就是对(a[i]-1)求和再加1(每一层的结点都集中在上一层的一个结点上)
同理,我们考虑最少能有多少叶子结点,就是把上一个的答案再减去min(a[i]-1, a[i-1]-1)的求和,就是每一层的结点都尽可能的分散在上一层的结点
根据这个,那么如果要求有k个叶子节点,k在最大值与最小值之间,就可以生成出这棵树了
生成的方法,和构造起来差不多,就是先求出最大值与k的差T,然后每一层处理时,如果T>0,就使这一层尽可能的分散在上一层结点上,然后T减少一点
直到T为0,之后的层都直接集中在上一层的一个结点即可
详情见代码
1 #include<cstdio>
2 #include<algorithm>
3 #include<cstring>
4 using namespace std;
5
6 int n,t,k,a[200200],s1,s2;
7
8 int main()
9 {
10 scanf("%d %d %d",&n,&t,&k);
11 for(int i=1;i<=t;++i) {scanf("%d",a+i);s1+=a[i];}s1-=t-1;
12 s2=s1;for(int i=2;i<=t;++i) s2-=min(a[i]-1,a[i-1]-1);
13 if(s2<=k&&k<=s1)
14 {
15 printf("%d
",n);
16 for(int i=2;i<=a[1]+1;++i) printf("1 %d
",i);//先处理1
17 int tot=2+a[1],cnt=s1-k;
18 for(int i=2;i<=t;++i)
19 {
20 int tt=min(a[i]-1,a[i-1]-1),cou=0;//tt是第i深度形成的边数
21 while(cnt&&tt)
22 {
23 if(cou) {tt--,cnt--;}
24 printf("%d %d
",tot-a[i-1]+cou,tot+cou);//每次都+1
25 cou++;
26 }
27 if(cnt==0||tt==0)//若还有多余的边,则加到第一个结点
28 {
29 while(cou<a[i])
30 printf("%d %d
",tot-a[i-1],tot+cou++);
31 }
32 tot+=a[i];//结点序增加
33 }
34 }
35 else puts("-1");
36 }