• 消息传递 树形DP


    非常妙的树形DP:由于n很小,我们可以枚举每一个点作为第一个节点,计算其时间花费

    那么问题就转化为对于给点节点求花费时间。

    通过观察,显然我们会发现先传给花费时间多的人更加合算,因为这样可以最大限度的避免

    一个人还在辛苦的传递信息,另一个人却悠闲的喝下午茶(雾)的局面

    所以我们可以每次都记录下对于一个节点而言,它的所有子节点的时长,

    并对其排序,排序后先传给耗时最多的人,但这样传递了之后,由于耗时最多的人最先被传递,

    那么这个本应耗时最多的人就不一定还是耗时最多的人了,因此我们要分别计算所有子节点

    的耗时,并取max计入ans,最后dp数组即代表一旦这个节点得知消息,要多久才可以把消息传给 所有其他的人(除了传给它的那个人),即完成任务。树的结构保证了其正确性

    why是ans=min(son[i]+cnt-i+1)?

    因为这里为了方便是从小到大排序,又因为是优先大的

    cnt-i即为还有多少个才能到它,然后+1是因为高斯这个点信息需要1的时间。

    son[i]则是加上自身的时间

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define AC 1100
     4 #define ACway 2500
     5 #define R register int
     6 #define D printf("line in %d
    ",__LINE__);
     7 int n;
     8 int Head[AC],Next[ACway],date[ACway],tot;
     9 int ans[AC],minn=INT_MAX,f[AC];//use用来存储每个节点的儿子(DFS中临时存储)
    10 inline int read()
    11 {
    12     int x=0;char c;
    13     while(isspace(c=getchar()));
    14     while(c>='0' && c<='9')x=x*10+c-'0',c=getchar();
    15     return x;
    16 }
    17 
    18 inline void add(int f,int w)
    19 {
    20     date[++tot]=w , Next[tot]=Head[f] , Head[f]=tot;
    21     date[++tot]=f , Next[tot]=Head[w] , Head[w]=tot; 
    22 }   
    23 
    24 void upmax(int &a,int b)
    25 {
    26     if(b>a)a=b;
    27 }
    28 
    29 void upmin(int &a,int b)
    30 {
    31     if(b<a)a=b;  
    32 }
    33 
    34 void DFS(int x,int fa)
    35 {
    36     R now;
    37     int cnt=0,son[AC];//开在DFS里面更加方便?
    38     for(R i=Head[x]; i ;i=Next[i])//枚举子节点
    39     {
    40         now=date[i];
    41         if(now!=fa)//如果不是父亲,即为儿子
    42         {
    43             DFS(now,x);
    44             son[++cnt]=f[now];
    45         }
    46     }
    47     sort(son+1,son+cnt+1);
    48     for(R i=1;i<=cnt;i++) upmax(f[x],son[i]+cnt-i+1);
    49 }
    50 
    51 void pre()
    52 {
    53     R a;
    54     n=read();
    55     for(R i=2;i<=n;i++)
    56     {
    57         a=read();//读入i的上级
    58         add(a,i);
    59     }
    60 }
    61 
    62 void work()
    63 {
    64     for(R i=1;i<n;i++)//枚举第一个节点
    65     {
    66         memset(f,0,sizeof(f));
    67         DFS(i,0);
    68         ans[i]=f[i];//ans[i]存以i为第一个节点的最小耗时
    69         upmin(minn,ans[i]);
    70     }
    71     printf("%d
    ",minn+1);//还包括告诉别人的时间
    72     for(R i=1;i<=n;i++) 
    73         if(ans[i]==minn) printf("%d ",i);
    74 }
    75 
    76 int main()
    77 {
    78 //  freopen("in.in","r",stdin);
    79     pre();
    80     work();
    81 //  fclose(stdin);
    82     return 0;
    83 }
  • 相关阅读:
    mysql赋权限
    MySQL Server 5.6安装
    Class.isAssignableFrom(Class clz)方法 与 instanceof 关键字的区别
    每天一个linux命令
    解锁scott用户
    堆栈的理解
    类与对象的理解
    数组copy
    ArrayList 的代码
    intput/output 文件的复制练习
  • 原文地址:https://www.cnblogs.com/ww3113306/p/8762959.html
Copyright © 2020-2023  润新知