Codeforces Round #386 (Div. 2)G. New Roads [构造][树]

题目链接: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",n);
16         for(int i=2;i<=a[1]+1;++i) printf("1 %d\n",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\n",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\n",tot-a[i-1],tot+cou++);
31             }
32             tot+=a[i];//结点序增加
33         }
34     }
35     else puts("-1");
36 }
View Code

 

posted @ 2016-12-22 19:09  遗风忘语  阅读(117)  评论(0编辑  收藏  举报