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 }