Codeforces Round #135 (Div. 2) D. Choosing Capital for Treeland 树形DP

链接:

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

题意:

给出一棵树,但是它的边是有向边,选择一个城市,问最少调整多少条边的方向能使一个选中城市可以到达所有的点,输出最小的调整的边数,和对应的点。

题解:

定义dp0,dp1,dp三个数组

dp0[i]表示i到树根有多少个需要反转

dp1[i]表示i到所有的后代有多少需要反转

第一次dfs求出这两个

然后第二次dfs就能直接算dp[i]了,dp[i]表示的就是题目所要求的

代码:

31 int n;
32 vector<PII> G[MAXN];
33 int dp[MAXN], dp0[MAXN], dp1[MAXN];
34 
35 void dfs(int u, int par) {
36     if (G[u].size() == 1 && par != -1) return;
37     rep(i, 0, G[u].size()) {
38         int to = G[u][i].first;
39         int dir = G[u][i].second;
40         if (to == par) continue;
41         dp0[to] = dp0[u];
42         if (dir == 1) dp0[to]++;
43         dfs(to, u);
44         dp1[u] += dp1[to];
45         if (dir == -1) dp1[u]++;
46     }
47 }
48 
49 void dfs2(int u, int par) {
50     if (G[u].size() == 1 && par != -1) return;
51     rep(i, 0, G[u].size()) {
52         int to = G[u][i].first;
53         int dir = G[u][i].second;
54         if (to == par) continue;
55         if (dir == 1) dp[to] = dp[u] + 1;
56         else dp[to] = dp[u] - 1;
57         dfs2(to, u);
58     }
59 }
60 
61 int main() {
62     ios::sync_with_stdio(false), cin.tie(0);
63     cin >> n;
64     rep(i, 1, n) {
65         int u, v;
66         cin >> u >> v;
67         G[u].pb(mp(v, 1));
68         G[v].pb(mp(u, -1));
69     }
70     dfs(1, -1);
71     dp[1] = dp1[1];
72     dfs2(1, -1);
73     int ans = INF;
74     rep(i, 1, n + 1) ans = min(ans, dp[i]);
75     cout << ans << endl;
76     rep(i, 1, n + 1) if (dp[i] == ans) cout << i << ' ';
77     cout << endl;
78     return 0;
79 }

 

posted @ 2017-08-11 15:11  Flowersea  阅读(122)  评论(0编辑  收藏  举报