zoukankan      html  css  js  c++  java
  • 【Helvetic Coding Contest 2018】B2. Maximum Control (medium)

    Description

      传送门(翻译就别想了,本人英语太垃圾)

    Solution

      设ans[i]为设置i个船时能控制的最多星球数(看到这你可能因为是dp,然而我可以很负责地告诉你是假的)

      首先一个显然的结论,ans[1]=1,ans[2]=树的直径长

      有由B1题的提示我们也可以得到一个显然的结论,要使控制数最多,其实只有叶子节点是有用的

      如果这样,那就比较容易了。

      我们可以先找出树的直径,然后从直径上的点向外扩展,记录每个节点的深度(叶子节点深度为一个常数,反正只要一样又不会爆类型就无所谓)

      为什么这样呢?

      因为在选择时,当该节点被控制的时候,一定是以该节点为根的子树深度最大的叶子节点被放了船(这样才会使得答案最大)

      那最后这步就较为容易了,枚举直径上的点,向外扩展,每扩展到一个新节点,就将该节点能控制的星球数+1,在将这个数字向该节点深度最大的儿子传递,向其他儿子传递的的数字即为0(或1主要看如何实现,如果计数从叶子

      节点+1的话就0,否则1,讲的不清楚,反正大家都懂对吧,不然看下代码也能懂的)

      最后必然每个叶子节点都有自己能控制的星球数且这些控制互不干扰,并且一定最

      那么我们只需要sort一下,然后贪心计算答案就好了

      其实本题不找直径也行,只需把直径的一个端点找到,然后情况其实是可以合并在一起的

      比赛时就是这样打,本来以为是乱搞过了,结果一看题解跟我想法一样也是很神奇233

      代码~~~

     1 #include<cstdio>
     2 #include<queue>
     3 #include<cstring>
     4 #include<algorithm>
     5 std::queue<int> q;
     6 struct r{
     7     int last,to;
     8 }e[200050];
     9 bool v[100050];
    10 int d[100050],num=1,fa[100050],ans[100050],a,t,b,n,head[100050],res,p,dep[100050],son[100050],val[100050];
    11 void add(int u,int vv){e[num].to=vv,e[num].last=head[u];head[u]=num++;}
    12 void bfs(int u){
    13     q.push(u);
    14     memset(d,63,sizeof d);
    15     d[u]=0;
    16     while (!q.empty()){
    17         int now=q.front(),y;q.pop();
    18         for (int i=head[now];i;i=e[i].last)if (d[y=e[i].to]>d[now]+1){
    19             d[y]=d[now]+1;
    20             fa[y]=now;
    21             q.push(y);
    22             if (d[y]>res)res=d[y],p=y;
    23         }
    24     }
    25 }
    26 void dfs(int u,int f){
    27     for (int i=head[u];i;i=e[i].last)if (!v[e[i].to]&&e[i].to!=f){
    28         dfs(e[i].to,u);
    29         if (dep[e[i].to]>=dep[u])dep[u]=dep[e[i].to]+1,son[u]=e[i].to;
    30     }
    31 }
    32 void dfs1(int u,int s,int f){
    33     bool flag=0;
    34     for (int i=head[u];i;i=e[i].last)if (!v[e[i].to]&&e[i].to!=f){
    35         if (e[i].to!=son[u])dfs1(e[i].to,1,u);
    36         else dfs1(e[i].to,s+1,u);
    37         flag=1;
    38     }
    39     if (!flag&&!v[u])val[++t]=s;
    40 }
    41 bool cmp(int a,int b){return a>b;}
    42 int main(){
    43     scanf("%d",&n);
    44     if (n==1){
    45         printf("1
    ");
    46         return 0;
    47     }
    48     int u,vv;
    49     for (int i=1;i<n;i++)scanf("%d%d",&u,&vv),add(u,vv),add(vv,u);
    50     ans[1]=1;
    51     bfs(1);int st=p;res=0;
    52     bfs(p);int ed=p;
    53     while (st!=ed){
    54         v[ed]=1;
    55         ed=fa[ed];
    56     }
    57     v[st]=1;
    58     ans[2]=res+1;
    59     ed=p;
    60     while (st!=ed){
    61         dfs(ed,-1);
    62         dfs1(ed,0,-1);
    63         ed=fa[ed];
    64     }
    65     std::sort(val+1,val+t+1,cmp);
    66     for (int i=1;i<=t;i++)ans[i+2]=ans[i+1]+val[i];
    67     for (int i=t+3;i<=n;i++)ans[i]=n;
    68     for (int i=1;i<=n;i++)printf("%d ",ans[i]);
    69 }
    View Code

     

  • 相关阅读:
    input上传mp3格式文件,预览并且获取时间
    jquery 页面input上传图后显示
    将String类型的字符串拼接成以逗号分隔的字符输出
    layui select多选下拉显示 以及回显
    input输入框只能输入数字和英文逗号
    电脑开机右下角有小金锁,并且提示一分钟后重启电脑
    修改tomcat控制台的标题
    VC防止程序被多次运行 互斥体方法
    VC中遍历进程并获取进程信息
    VC中遍历目标进程中的模块
  • 原文地址:https://www.cnblogs.com/Cool-Angel/p/8862649.html
Copyright © 2011-2022 走看看