• 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);
    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 }
    View Code
  • 相关阅读:
    SSH-框架工作笔记
    Ajax基础
    Hibernate基础
    Struts1 中的国际化
    MyEclipse中的快捷键
    Oracle_存储过程
    oracle_开发子程序和包
    常用的正则表达式
    jQuery中的事件
    AcWing 1118. 分成互质组
  • 原文地址:https://www.cnblogs.com/chendl111/p/6212521.html
Copyright © 2020-2023  润新知