zoukankan      html  css  js  c++  java
  • hdu6867 Tree // DFS

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6867

    大意:给定一棵以1为固定顶点的树,你可以从任意一个父亲节点走到其儿子节点。让你新建一条边,这条边上可以双向通行。求可抵达的点对数,主意node[i]可以抵达自身node[i]。

    这题一上来就想用贪心(是错的),感觉上好像挺对的。找一条最长的路径,看似可以新抵达的点更多。

    实际上此题还与各节点的子树大小具有密切关系。然而我虽然发现了这一点,最后写的搜索竟然TLE。临场还是不行。。第二天写了几分钟就A了。。。

    key:

    考虑不加边: 每个节点可以去到的点的个数即为其自身,以及不包括自身的子树大小。设节点i的后代个数(子树大小-1)为son[i],则这些点对的个数总和就是n + ∑1,n (son[i])

    第一次dfs_son()填满son[]

    考虑加了一条边:首先,加边的点必定位于某条路径的末端与初始根节点1之间,这点显而易见。加边之后,收益增加的点为这条路径上除了1以外的节点。设有k个好了。那对于这k个节点中编号为i的节点,增加的点对则是  n减去包含其自身的子树大小,也即n-1-son[i]。任务就很明确了。

    第二次dfs统计每条路径末端求得的∑(n-1-son[i]),取其中的最大值,再与1中总和相加即为结果

    *转载请附链接 谢谢

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<string>
     5 #include<cstdio>
     6 #include<iomanip>
     7 #include<vector>
     8 #include<queue>
     9 
    10 #define ll long long
    11 using namespace std;
    12 const int maxn = 5e5 + 10;
    13 
    14 int n;
    15 ll ans = 0;
    16 
    17 int son[maxn];
    18 19 
    20 vector<int> v[maxn];
    21 
    22 int dfs_son(int now)
    23 {
    24     int cnt = 0;
    25     ll tmp = 0;
    26     for(int i = 0 ; i < v[now].size() ; i++){
    27         int k = v[now][i];
    28         cnt++;
    29         tmp += dfs_son(k);
    30     }
    31     if(cnt == 0){
    32         son[now] = 1;
    33     }else{
    34         son[now] = tmp + 1;
    35     }    
    36     return son[now];
    37 }
    38 
    39 void dfs_res(int now, bool *vis, ll sum)
    40 {
    41     if(son[now] == 0)    ans = max(ans, sum);
    42     for(int i = 0 ; i < v[now].size() ; i++){
    43         int nxt = v[now][i];
    44         if(vis[nxt] == true)    continue;
    45         vis[nxt] = true;
    46         dfs_res(nxt, vis, sum + n-1-son[nxt]);
    47         vis[nxt] = false;
    48     }
    49     return ;
    50 }
    51 
    52 int main(){
    53     int T;scanf("%d",&T);
    54     while(T--){
    55         scanf("%d",&n);
    56         ans = 0;
    57         for(int i = 0 ; i <= n ; i++){
    58             son[i] = 0;
    59             v[i].clear();
    60         }
    61         
    62         for(int i = 2 ; i <= n ; i++){
    63             int father;
    64             scanf("%d",&father);
    65             v[father].push_back(i);//反向
    66         }
    67         
    68         dfs_son(1);//求每个节点的儿子个数
    69         
    70         ll sum = 0;//所有节点的儿子和 
    71         for(int i = 1 ; i <= n ; i++){
    72             son[i] -= 1;
    73             sum += son[i];
    74         }
    75         
    76         bool vis[maxn];
    77         vis[1] = true;
    78         dfs_res(1, vis, 0);
    79         
    80         ans += sum + n;
    81         printf("%lld
    ",ans);
    82     }
    83         
    84     return 0;
    85 }
  • 相关阅读:
    浅析ES6中的iterator
    nodejs中的异步回调机制
    用好js与nodejs中的try...catch
    vscode设置html默认浏览器
    nodejs中相互引用(循环引用)的模块分析
    ES6—带默认值的函数参数及其作用域
    函数声明与函数表达式的区别
    let块级引起的闭包思考
    进程与线程
    angular(^4)-监控表格按键行为的问题
  • 原文地址:https://www.cnblogs.com/ecustlegendn324/p/13531727.html
Copyright © 2011-2022 走看看