1. 程式人生 > >UVALive - 4287 - Proving Equivalences(強連通分量)

UVALive - 4287 - Proving Equivalences(強連通分量)

tar size 連通 als pre input bsp ios .com

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 }

UVALive - 4287 - Proving Equivalences(強連通分量)