标签:
一个国家,有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 }
CF 219D Choosing Capital for Treeland 树形DP 好题
标签:
原文地址:http://www.cnblogs.com/-maybe/p/4746443.html