• Codeforces 219D Choosing Capital for Treeland:Tree dp


    题目链接:http://codeforces.com/problemset/problem/219/D

    题意:

      给你一棵树,n个节点。

      树上的边都是有向边,并且不一定是从父亲指向儿子的。

      你可以任意翻转一些边的方向。

      现在让你找一个节点,使得从这个节点出发能够到达其他所有节点,并保证翻转边的数量最小。

      问你最少翻转多少条边,并输出所有满足此条件的节点编号。

    题解:

      本题要解两个dp: dp1 & dp2

      首先考虑dp1:

        表示状态:

          dp1[i]表示使节点i能够到达i的子树中的所有节点,翻转边的最小数量。

        如何转移:

          dp1[i] = ∑ (dp1[son] + 边<i,son>由i指向son ? 0 : 1)

          dfs一遍即可。

      然后求dp2:

        表示状态:

          dp2[i]表示使节点i能够到达这棵树的所有节点,翻转边的最小数量。

        如何转移:

          dp2[i] = dp2[par] + 边<par,i>是否由par指向i ? 1 : -1

          如果边<par,i>由par指向i,那么在dp2[par]中这条边是不会被翻转的,所以此时应该将它翻转,代价+1。

          如果边<par,i>由i指向par,那么在dp2[par]中这条边已经被翻转了一次,然而在dp2[i]中是不需要翻转的,所以将dp2[par]中多余的那次翻转减掉就好。

        边界条件:

          dp2[1] = dp1[1]

          (默认根节点为1)

      所以最终答案为dp2[i]中的最小值,然后将所有dp2[i]等于ans的节点输出就好啦。

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #include <vector>
     5 #define MAX_N 200005
     6 #define INF 1000000000
     7 
     8 using namespace std;
     9 
    10 struct Edge
    11 {
    12     int dest;
    13     bool flag;
    14     Edge(int _dest,bool _flag)
    15     {
    16         dest=_dest;
    17         flag=_flag;
    18     }
    19     Edge(){}
    20 };
    21 
    22 int n;
    23 int ans=INF;
    24 int dp1[MAX_N];
    25 int dp2[MAX_N];
    26 vector<Edge> edge[MAX_N];
    27 
    28 void read()
    29 {
    30     cin>>n;
    31     int x,y;
    32     for(int i=1;i<n;i++)
    33     {
    34         cin>>x>>y;
    35         edge[x].push_back(Edge(y,true));
    36         edge[y].push_back(Edge(x,false));
    37     }
    38 }
    39 
    40 void dfs1(int now,int p)
    41 {
    42     dp1[now]=0;
    43     for(int i=0;i<edge[now].size();i++)
    44     {
    45         Edge temp=edge[now][i];
    46         if(temp.dest!=p)
    47         {
    48             dfs1(temp.dest,now);
    49             dp1[now]+=dp1[temp.dest]+(!temp.flag);
    50         }
    51     }
    52 }
    53 
    54 void dfs2(int now,int p,bool d)
    55 {
    56     if(now==1) dp2[now]=dp1[now];
    57     else dp2[now]=dp2[p]+(d?1:-1);
    58     ans=min(ans,dp2[now]);
    59     for(int i=0;i<edge[now].size();i++)
    60     {
    61         Edge temp=edge[now][i];
    62         if(temp.dest!=p) dfs2(temp.dest,now,temp.flag);
    63     }
    64 }
    65 
    66 void work()
    67 {
    68     dfs1(1,-1);
    69     dfs2(1,-1,233);
    70     cout<<ans<<endl;
    71     for(int i=1;i<=n;i++)
    72     {
    73         if(dp2[i]==ans) cout<<i<<" ";
    74     }
    75     cout<<endl;
    76 }
    77 
    78 int main()
    79 {
    80     read();
    81     work();
    82 }
  • 相关阅读:
    树莓派4B
    SpringBoot 自定义 info Actuator 原理
    RestTemplate翻译serviceId过程
    ISA, ABI, API区别
    01.编译器结构
    【Git123】Git SSH Key支持多账号
    【消息中间件123】Solace PubSub+ Event Broker介绍
    【ETL123】
    【Http123】Http Timeout
    【性能123】Linux性能之“平均负载”
  • 原文地址:https://www.cnblogs.com/Leohh/p/8256852.html
Copyright © 2020-2023  润新知