codeforces 219D Choosing Capital for Treeland

D. Choosing Capital for Treeland 

http://codeforces.com/problemset/problem/219/D

 1 /*
 2 CodeForces D. Choosing Capital for Treeland (转化为树形DP)
 3 题意:给一个n节点的有向无环图,要找一个这样的点:
 4 该点到其它n-1要逆转的道路最少,(边<u,v>,如果v要到u去,则要逆转该边方向)
 5 如果有多个这样的点,则升序输出所有
 6 
 7 思路:把边的方向化为权值,正向为1,逆向为0。
 8 问题转化为找哪些点的在遍历全图后总权值最大。
 9 这就是树形DP了,考虑每个节点,它可以从子树收获价值,也可以从父亲收获。
10 所以dfs两遍,一边把子树的价值存到dps[i]里,再一遍把父亲的价值存到dpf[i]里。
11 ans[i] = dps[i] + dpf[i]。
12 
13 */
14 
15 #include<cstdio>
16 #include<algorithm>
17 #include<cstring>
18 
19 using namespace std;
20 
21 const int MAXN = 200010;
22 const int MAXM = 500010;
23 
24 struct Edge{
25     int to,nxt,w;
26 }e[MAXM];
27 struct ANS{
28     int id,v;
29     bool operator < (const ANS &a) const {
30         if (v==a.v) return id < a.id;
31         return v > a.v;
32     }
33 }ans[MAXN];
34 int head[MAXM],tot;
35 int dps[MAXN],dpf[MAXN];
36 
37 
38 inline int read() {
39     int x = 0,f = 1;char ch = getchar();
40     for (; ch<'0'||ch>'9'; ch = getchar())
41         if (ch=='-') f = -1;
42     for (; ch>='0'&&ch<='9'; ch = getchar())
43         x = x*10+ch-'0';
44     return x*f;
45 }
46 
47 inline void add_edge(int u,int v,int w) {
48     e[++tot].to = v,e[tot].w = w,e[tot].nxt = head[u],head[u] = tot; 
49 }
50 
51 void dfs1(int u,int fa) {
52     for (int i=head[u]; i; i=e[i].nxt) {
53         int v = e[i].to,w = e[i].w;
54         if (v==fa) continue;
55         dfs1(v,u); // 叶 -> 根 
56         dps[u] += dps[v]+w;
57     }
58 }
59 void dfs2(int u,int fa) {
60     for (int i=head[u]; i; i=e[i].nxt) {
61         int v = e[i].to,w = e[i].w;
62         if (v==fa) continue;
63         dpf[v] += (w?0:1)+dpf[u]+dps[u]-dps[v]-w;
64         dfs2(v,u); //根 -> 叶 
65     }
66 }
67 
68 int main() {
69     
70     int n = read();
71     for (int u,v,i=1; i<n; ++i) {
72         u = read(),v = read();
73         add_edge(u,v,1),add_edge(v,u,0);
74     }
75     dfs1(1,0);
76     dfs2(1,0);
77     
78     for (int i=1; i<=n; ++i) {
79         ans[i].v = dps[i]+dpf[i];
80         ans[i].id = i;
81     }
82     sort(ans+1,ans+n+1);
83     
84     int sum = n-1-ans[1].v,cnt = 1;
85     for (int i=2; i<=n; ++i) 
86         if (ans[i].v==ans[1].v) cnt++;
87         else break;
88     
89     printf("%d\n",sum);
90     for (int i=1; i<=cnt; ++i) {
91         printf("%d ",ans[i].id);
92     }
93     return 0;
94 }

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/9585095.html