zoukankan      html  css  js  c++  java
  • codeforces 219D 树形dp

    题目大意:

    根据n个城市,设置n-1条有向边,希望设定一个中心城市,能通过修改一些道路的方向到达任何一座城市,希望修改的道路数量最少

    输出这个最少的道路数量,并且把所有符合的可作为中心的城市编号一个个输出来

    开始也实在想不出,根据树形dp,首先要确定一棵树,可是这里的边乱七八糟的,没法确定根

    后来看了别人的思路,原来还是自己太死脑筋了,根本不需要确定根,可以把任意一个城市作为根来解决题目,这里假定1为根

    把所有的有向边看作无向边,但要记录那条边是真实存在的,哪条是自己加的

    用dp[i]表示 i 点到达其对应的子树中的所有点需要修改的边的数量

    用一次dfs得到dp[i]

    然后网上的大牛们都说2次dfs,后一次因为没写清楚,自己也不想看代码,就自己想了,可就是没办法写出dfs,最后发现直接就可以循环做。。。而且更好理解

    做法:

    len[i]记录 i 到 root 这里定义root为 1 长度,也就是i 到 1 之间有多少条边

    change[i] 表示这 len[i]条边中有多少条改变了

    这两个值可以在第一次dfs中实现

    然后对于每一个点 i 来说,其实为了让 i 能够到达任何一点,只要改动 i 到 1 这len[i]条边即可,画个图很容易发现

    1作为树根,i 到 1 的过程经过的都是一棵棵子树的根,能到达这些子树的根,必能到达子树中的任何一点,所以希望能够到达 1 即可

    用rec[i]记录以 i 为中心城市需要改动的边

    rec[i] = dp[1] - change[i] + (len[i] - change[i]) //减第一个change[i]是把原来改过的边改回来,然后+后面的是因为为了 i 到1,需要将那些

    方向正常的 len[i] - change[i]倒转

    最后通过rec[i]得到答案即可= =

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 const int N = 200005;
     6 
     7 int first[N] , k , len[N] , change[N] , dp[N] , rec[N];
     8 
     9 struct Edge{
    10     int y , next;
    11     bool flag;
    12 }e[N<<1];
    13 
    14 void add_edge(int x , int y , bool flag)
    15 {
    16     e[k].y = y , e[k].next = first[x] , e[k].flag = flag;
    17     first[x] = k++;
    18 }
    19 
    20 void dfs(int u , int fa)
    21 {
    22     for(int i = first[u] ; i!=-1 ; i=e[i].next){
    23         int v = e[i].y;
    24         if(v == fa) continue;
    25         len[v] = len[u]+1;
    26         change[v] = change[u];
    27         if(!e[i].flag) change[v]++;
    28         dfs(v , u);
    29         if(!e[i].flag){
    30             dp[u] += dp[v]+1;
    31         }
    32         else{
    33             dp[u] += dp[v];
    34         }
    35     }
    36 }
    37 
    38 int main()
    39 {
    40    // freopen("a.in" , "r" , stdin);
    41     int n , a , b;
    42     while(scanf("%d" , &n) == 1)
    43     {
    44         memset(first , -1 , sizeof(first));
    45         k = 0;
    46         for(int i=1 ; i<n ; i++){
    47             scanf("%d%d" , &a , &b);
    48             add_edge(a , b , true);
    49             add_edge(b , a , false);
    50         }
    51         memset(dp , 0 , sizeof(dp));
    52         len[1] = 0 , change[1] = 0;
    53         dfs(1 , -1);
    54 
    55         int minn = 200000000;
    56 
    57         for(int i=1 ; i<=n ; i++){
    58             rec[i] = dp[1] + len[i] - 2*change[i];
    59            // cout<<"i: "<<i<<" "<<len[i]<<" "<<change[i]<<" "<<rec[i]<<endl;
    60             minn = min(minn , rec[i]);
    61         }
    62         printf("%d
    " , minn);
    63         int num = 0;
    64         for(int i=1 ; i<=n ; i++){
    65             if(minn == rec[i]){
    66                 if(num == 0) printf("%d" , i);
    67                 else printf(" %d" , i);
    68                 num ++;
    69             }
    70         }
    71         printf("
    ");
    72     }
    73     return 0;
    74 }
  • 相关阅读:
    matplotlib数据可视化之柱形图
    xpath排坑记
    Leetcode 100. 相同的树
    Leetcode 173. 二叉搜索树迭代器
    Leetcode 199. 二叉树的右视图
    Leetcode 102. 二叉树的层次遍历
    Leetcode 96. 不同的二叉搜索树
    Leetcode 700. 二叉搜索树中的搜索
    Leetcode 2. Add Two Numbers
    Leetcode 235. Lowest Common Ancestor of a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4232633.html
Copyright © 2011-2022 走看看