树形DP

https://vjudge.net/contest/237352#problem/H

题意:有n个点,给出n-1条有向边,这些边不一定使得每个点都能走到其他任意点,但是可以变换边的方向满足上述条件。要求选择一个点作为首都,通过改变某些边的方向,使得该点能走到任意点,问最少需要更改多少条边?输出最少边数,并输出可以作为首都的点的编号。

解法:通过dfs,计算以1为根,需要变化的边数。定义dp[u]为以u为根的子树中要使根都可达,需要调换方向的边的条数。定义dir[v]记录点v到父亲节点的边的方向。则dp[u] += (dp[vi] + dir[vi])(u的所有子节点vi,除了u的父节点)(若u->v,则dir[v]=0;否则dir[v]=1)

计算出dp[1]后,开始第二轮dfs。dp[u]换成新的定义,以u为根的到达整棵树需要调整的边的条数。此时dp[u] = dp[p] + dir[u]?1:-1(p为u的父节点)

参考博客:https://blog.csdn.net/qq_24451605/article/details/48676619

 1 //#include<bits/stdc++.h>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <string>
 7 #include <cmath>
 8 #include <cstdlib>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <vector>
13 #include <set>
14 #include <bitset>
15 #include <iomanip>
16 #define ms(a, b) memset(a, b, sizeof(a));
17 using namespace std;
18 typedef long long LL;
19 typedef pair<int, int> pii;
20 const int INF = 0x3f3f3f3f;
21 const int maxn = 2e5 + 10;
22 const int MAXN = 2e4 + 10;
23 const double eps = 1e-8;
24 const int mod = 1e9 + 7;
25 int n;
26 vector<pii> v[maxn];
27 int dp[maxn];
28 
29 void dfs(int t, int s) {
30     dp[t] = 0;
31     for(int i = 0; i < v[t].size(); i++) {
32         pii k = v[t][i];
33         if(k.first == s) continue;
34         dfs(k.first, t);
35         dp[t] += dp[k.first] + k.second;
36     }
37     return;
38 }
39 
40 void solve(int t, int s) {
41     for(int i = 0; i < v[t].size(); i++) {
42         pii tmp = v[t][i];
43         int k = tmp.first;
44         int f = tmp.second;
45         if(k == s) continue;
46         dp[k] = dp[t] + (f ? -1 : 1);
47         solve(k, t);
48     }
49     return ;
50 }
51 
52 
53 int main() {
54 #ifdef local
55     freopen("case.in", "r", stdin);
56 //    freopen("case.out", "w", stdout);
57 #endif
58 //    ios::sync_with_stdio(false);
59 //    cin.tie(0);
60     scanf("%d", &n);
61     for(int i = 0; i < n-1; i++) {
62         int s, t;
63         scanf("%d%d", &s, &t);
64         v[s].push_back(make_pair(t, 0));
65         v[t].push_back(make_pair(s, 1));
66     }
67     dfs(1, -1);
68 //    for(int i = 1; i <= n; i++) cout << dp[i] << " ";
69 //    cout << endl;
70     solve(1, -1);
71     //
72 //    for(int i = 1; i <= n; i++) cout << dp[i] << " ";
73 //    cout << endl;
74     //
75     int ans = INF;
76     for(int i = 1; i <= n; i++)
77         ans = min(ans, dp[i]);
78     printf("%d\n", ans);
79     for(int i = 1; i <= n; i++)
80         if(dp[i] == ans) printf("%d ", i);
81     printf("\n");
82 //    solve();
83     return 0;
84 }

 

posted @ 2018-08-07 23:31  Sissi_hss  阅读(118)  评论(0)    收藏  举报