zoukankan      html  css  js  c++  java
  • UVALive

    题意:n个点连成的生成树(n个点,n-1条边,点与点之间都连通),如果某个点在两点之间的路径上,那这个点的繁荣度就+1,问你在所有点中,最大繁荣度是多少?就比如上面的图中的C点,在A-B,A-D,A-E,A-F,B-D,B-E,B-F的路径上,所以繁荣度为7。

    思路:我们可以想一下,繁荣度是怎么来的?假设一个点的度是2,相当于以这个点为根,有两棵子树,那繁荣度就是这两棵子树上各取一个点两两组合,最后的结果就是两棵子树上的点的乘积。所以不难推出,若度大于2,那繁荣度就是所有子树上的点树两两相乘的和,例如上图的C点,度为3,且3个度包含的点的个数分别为1,1,3,繁荣度 = 1*1 + 1*3 + 1*3 = 7。

    然而,这样的计算方式复杂度有点高,若度为n,光计算繁荣度就要O(n*n),更何况这只是一个点的繁荣度。所以,我们还可以简化一下计算方式:

    计算出每一棵子树的点的个数,用每个子树的点的个数乘以除了这棵子树以及根节点以外剩余的点,,每棵子树都这样计算,并将结果相加,求出的和除以2,就是结果。

    因为这样的计算方式和之前相比,相当于两两之间都乘了两次,子树1*所有子树的和(除自己) = 子树1*子树2* + 子树1*子树3 + .....  + 子树1*子树n, 子树2*所有子树的和(除自己) = 子树2*子树1 + 子树2*子树3 + ... + 子树2*子树n;这之中,子树1*子树2 ,又子树2*1子树,计算了两次,所以最终结果要除以2。

    我们可以将整个图看成一棵以节点1为根的树,这样将会简化很多。除此之外,还可以使用链式前向星,记录下某个点与哪些点直接相连。这样,就可以节省寻找子树的时间

    具体看代码:

     1 #include<iostream> 
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<string>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<stack>
     8 #include<climits>
     9 #include<queue>
    10 #define eps 1e-7
    11 #define ll long long
    12 #define inf 0x3f3f3f3f
    13 #define pi 3.141592653589793238462643383279
    14 using namespace std;
    15 const int maxn = 20007;
    16 int head[maxn],num,n;
    17 ll ans,sum,size[maxn];
    18 struct node{
    19     int to,next;
    20 }edge[maxn<<1];
    21 
    22 void add(int u,int v) //使用链式前向星计算每个点于那些点直接相连 
    23 {
    24     edge[num].to = v;
    25     edge[num].next = head[u];
    26     head[u] = num++;
    27 }
    28 
    29 void DFS(int u,int fa) //将整个图看成一棵树,u为当前节点,fa为父亲节点 
    30 {
    31     ll res = 0;
    32     size[u] = 1; //size[u]表示以u为根的树有多少个节点 
    33     for(int i=head[u]; i!=-1; i=edge[i].next) //遍历所有子树 
    34     {
    35         int to = edge[i].to;
    36         if(to == fa) continue; //不计算父亲节点 
    37         DFS(to,u);  
    38         size[u] += size[to]; //以u为根的树的节点总数等于他所有子树的节点树之和 
    39         res += (n - size[to] - 1)*size[to]; //计算子树与其他剩余点的乘积 
    40     }
    41     res += ( n - size[u] )*(size[u]-1); //除所有子树外,u的根节点连成的树也是以u为根的一课子树 
    42     ans = max(ans,res/2);
    43     return;
    44 }
    45 
    46 int main()
    47 {
    48     int t,cnt = 1;
    49     cin>>t;
    50     while(t--)
    51     {
    52         ans = -1;
    53         num = 0;
    54         memset(head,-1,sizeof(head));
    55         memset(size,0,sizeof(size));
    56         scanf("%d",&n);
    57         int start,end;
    58         for(int i=0; i<n-1; ++i)
    59         {
    60             scanf("%d%d",&start,&end);
    61             add(start,end); //start于end直接相连 
    62             add(end,start);//无向图,反过来也相连 
    63         }
    64         DFS(1,-1);
    65         printf("Case #%d: %lld
    ",cnt++,ans);
    66     }
    67     return 0;
    68 }
  • 相关阅读:
    strutr2运行流程
    ConcurrentHashMap原理分析
    面试题集锦
    jvm如何知道那些对象需要回收
    java中volatile关键字的含义
    关于Java类加载双亲委派机制的思考(附一道面试题)
    new关键字和newInstance()方法的区别
    Java中创建对象的5种方式 &&new关键字和newInstance()方法的区别
    字符串中第一个只出现一次的字符
    二进制数中1的个数
  • 原文地址:https://www.cnblogs.com/tuyang1129/p/9384631.html
Copyright © 2011-2022 走看看