Problem UVALive - 4287 - Proving Equivalences
Time Limit: 3000 mSec
Problem Description
Input
Output
Sample Input
2 4 0 3 2 1 2 1 3
Sample Output
4
2
题解:题意就是给出一个有向图,问最少添加几条有向边能够使得整张图强连通,Tarjan缩点是比较容易想到的,之后怎么办,要用到一个结论:如果图中有a个入度为零的点,b个出度为零的点,那么max(a, b)就是答案,这个东西不太容易严格证明(在一份ppt上看到说证明难,略。。。),但是形式上想一想还是挺对的。此外mark两个结论,这两个是很容易严格证明的:
1、DAG中唯一出度为0的点一定可以由任意点出发到达。(证明:由于无环,因此所有点都要终止在出度为0的点)
2、DAG中所有入度不为0的点一定可以由某个入度为0的点出发到达。(证明:由于无环,入度不为零的点逆着走一定终止在入度为0的点)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i, n) for (int i = 1; i <= (n); i++) 6 #define sqr(x) ((x) * (x)) 7 8 const int maxn = 20000 + 10; 9 const int maxm = 30 + 10; 10 const int maxs = 10000 + 10; 11 12 typedef long long LL; 13 typedef pair<int, int> pii; 14 typedef pair<double, double> pdd; 15 16 const LL unit = 1LL; 17 const int INF = 0x3f3f3f3f; 18 const LL mod = 1000000007; 19 const double eps = 1e-14; 20 const double inf = 1e15; 21 const double pi = acos(-1.0); 22 23 int n, m; 24 vector<int> G[maxn]; 25 int dfs_clock, scc_cnt; 26 int pre[maxn], sccno[maxn]; 27 stack<int> S; 28 29 int dfs(int u) 30 { 31 S.push(u); 32 int lowu = pre[u] = ++dfs_clock; 33 for (auto v : G[u]) 34 { 35 if (!pre[v]) 36 { 37 int lowv = dfs(v); 38 lowu = min(lowu, lowv); 39 } 40 else if (!sccno[v]) 41 { 42 lowu = min(lowu, pre[v]); 43 } 44 } 45 if (lowu == pre[u]) 46 { 47 scc_cnt++; 48 for (;;) 49 { 50 int t = S.top(); 51 S.pop(); 52 sccno[t] = scc_cnt; 53 if (t == u) 54 break; 55 } 56 } 57 return lowu; 58 } 59 60 void find_scc() 61 { 62 dfs_clock = scc_cnt = 0; 63 memset(pre, 0, sizeof(pre)); 64 memset(sccno, 0, sizeof(sccno)); 65 for (int i = 0; i < n; i++) 66 { 67 if (!pre[i]) 68 { 69 dfs(i); 70 } 71 } 72 } 73 74 int out[maxn], in[maxn]; 75 76 int main() 77 { 78 ios::sync_with_stdio(false); 79 cin.tie(0); 80 //freopen("input.txt", "r", stdin); 81 //freopen("output.txt", "w", stdout); 82 int T; 83 cin >> T; 84 while (T--) 85 { 86 memset(out, 0, sizeof(out)); 87 memset(in, 0, sizeof(in)); 88 cin >> n >> m; 89 for (int i = 0; i < n; i++) 90 { 91 G[i].clear(); 92 } 93 int u, v; 94 for (int i = 0; i < m; i++) 95 { 96 cin >> u >> v; 97 u--, v--; 98 G[u].push_back(v); 99 } 100 find_scc(); 101 for (int u = 0; u < n; u++) 102 { 103 for (auto v : G[u]) 104 { 105 if (sccno[v] != sccno[u]) 106 { 107 out[sccno[u]]++; 108 in[sccno[v]]++; 109 } 110 } 111 } 112 int a = 0, b = 0; 113 for (int i = 1; i <= scc_cnt; i++) 114 { 115 if (!out[i]) 116 a++; 117 if (!in[i]) 118 b++; 119 } 120 int ans = max(a, b); 121 if (scc_cnt == 1) 122 ans = 0; 123 cout << ans << endl; 124 } 125 return 0; 126 }