zoukankan      html  css  js  c++  java
  • CF 219D Choosing Capital for Treeland 树形DP 好题

    一个国家,有n座城市,编号为1~n,有n-1条有向边

    如果不考虑边的有向性,这n个城市刚好构成一棵树

    现在国王要在这n个城市中选择一个作为首都

    要求:从首都可以到达这个国家的任何一个城市(边是有向的)

    所以一个城市作为首都,可能会有若干边需要改变方向

    现在问,选择哪些城市作为首都,需要改变方向的边最少。

    输出最少需要改变方向的边数

    输出可以作为首都的编号

    树形DP

    先假定城市1作为首都

    令tree(i)表示以i为根的子树

    dp[i]表示在tree(i)中,若以i为首都的话,需要改变的边数

    第一次dfs,求出dp数组

    ans[i]表示在整棵树中,若以i为首都的话,需要改变的边数(注意和dp数组的意义的区别)

    明显:ans[1]=dp[1]

    明显有:

    在一棵有向树中,若首都为u,现在我们要让u的儿子节点v为首都,只需要改变1条边的方向

    假设节点u是节点v的父节点,e=(u,v),ans[u]已知

    若e的方向指向v,则:ans[v]=ans[u]+1

    否则:ans[v]=ans[u]-1

    所以第二次dfs,递推求出ans数组

    接着,找出min=min(ans[i]),并输出min

    输出所有使得ans[i]==min的i

      1 #include<cstdio>
      2 #include<cstring>
      3 
      4 using namespace std;
      5 
      6 const int maxn=200000+5;
      7 
      8 struct Edge
      9 {
     10     int to,next;
     11     bool flag;
     12 };
     13 Edge edge[maxn<<1];
     14 int head[maxn];
     15 int tot;
     16 int ans[maxn];
     17 int dp[maxn];
     18 int print[maxn];
     19 
     20 void init()
     21 {
     22     memset(head,-1,sizeof head);
     23     tot=0;
     24     memset(dp,0,sizeof dp);
     25 }
     26 
     27 void addedge(int u,int v,bool flag)
     28 {
     29     edge[tot].to=v;
     30     edge[tot].flag=flag;
     31     edge[tot].next=head[u];
     32     head[u]=tot++;
     33 }
     34 
     35 void dfs0(int ,int );
     36 void dfs1(int ,int );
     37 
     38 int main()
     39 {
     40     int n;
     41     init();
     42     bool cnt=true;
     43     scanf("%d",&n);
     44     for(int i=1;i<n;i++)
     45     {
     46         int u,v;
     47         scanf("%d %d",&u,&v);
     48         addedge(u,v,cnt);
     49         addedge(v,u,!cnt);
     50     }
     51     dfs0(1,-1);
     52     ans[1]=dp[1];
     53     dfs1(1,-1);
     54 
     55     int min=ans[1];
     56     for(int i=2;i<=n;i++)
     57     {
     58         if(ans[i]<min)
     59             min=ans[i];
     60     }
     61     tot=1;
     62     for(int i=1;i<=n;i++)
     63     {
     64         if(ans[i]==min)
     65         {
     66             print[tot++]=i;
     67         }
     68     }
     69 
     70     printf("%d
    ",min);
     71     for(int i=1;i<tot-1;i++)
     72     {
     73         printf("%d ",print[i]);
     74     }
     75     printf("%d
    ",print[tot-1]);
     76 
     77     return 0;
     78 }
     79 
     80 void dfs0(int u,int pre)
     81 {
     82     for(int i=head[u];~i;i=edge[i].next)
     83     {
     84         int v=edge[i].to;
     85         bool flag=edge[i].flag;
     86         if(v==pre)
     87             continue;
     88         dfs0(v,u);
     89         if(flag)
     90             dp[u]+=dp[v];
     91         else
     92             dp[u]+=(dp[v]+1);
     93     }
     94     return ;
     95 }
     96 
     97 void dfs1(int u,int pre)
     98 {
     99     for(int i=head[u];~i;i=edge[i].next)
    100     {
    101         int v=edge[i].to;
    102         int flag=edge[i].flag;
    103         if(v==pre)
    104             continue;
    105         if(flag)
    106             ans[v]=ans[u]+1;
    107         else
    108             ans[v]=ans[u]-1;
    109         dfs1(v,u);
    110     }
    111     return ;
    112 }
    View Code
  • 相关阅读:
    Chrome浏览器扩展开发系列之十四:本地消息机制Native messaging
    Chrome浏览器扩展开发系列之十三:消息传递Message
    Chrome浏览器扩展开发系列之十二:Content Scripts
    Chrome浏览器扩展开发系列之十一:NPAPI插件的使用
    Chrome浏览器扩展开发系列之十:桌面通知Notification
    《转载》使用CSS3 Flexbox布局
    CSS display属性的值及作用
    CSS中的各种居中方法总结
    《转载》详解 CSS 属性
    CSS3中新增的内容
  • 原文地址:https://www.cnblogs.com/-maybe/p/4746443.html
Copyright © 2011-2022 走看看