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 }