码迷,mamicode.com
首页 > Windows程序 > 详细

CF 219D Choosing Capital for Treeland 树形DP 好题

时间:2015-08-21 00:02:13      阅读:510      评论:0      收藏:0      [点我收藏+]

标签:

一个国家,有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\n",min);
 71     for(int i=1;i<tot-1;i++)
 72     {
 73         printf("%d ",print[i]);
 74     }
 75     printf("%d\n",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

 

CF 219D Choosing Capital for Treeland 树形DP 好题

标签:

原文地址:http://www.cnblogs.com/-maybe/p/4746443.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!