loj 1210 (求最少的加边数使得图变成强连通)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1210
思路:首先是缩点染色,然后重建并且统计新图中的每个点的入度和出度,于是答案就是max(入度为0的点的个数, 出度为0的点的个数,这里有一个trick就是如果scc_count == 1,那么应该输出0.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <stack> 6 using namespace std; 7 8 const int MAXN = (20000 + 20); 9 int n, m, NE; 10 struct Edge { 11 int v, next; 12 } edge[MAXN << 2]; 13 14 int head[MAXN]; 15 void Insert(int u, int v) 16 { 17 edge[NE].v = v; 18 edge[NE].next = head[u]; 19 head[u] = NE++; 20 } 21 22 int cnt, scc_count; 23 int low[MAXN], dfn[MAXN], color[MAXN]; 24 bool mark[MAXN]; 25 stack<int >S; 26 27 void Tarjan(int u) 28 { 29 low[u] = dfn[u] = ++cnt; 30 mark[u] = true; 31 S.push(u); 32 for (int i = head[u]; i != -1; i = edge[i].next) { 33 int v = edge[i].v; 34 if (dfn[v] == 0) { 35 Tarjan(v); 36 low[u] = min(low[u], low[v]); 37 } else if (mark[v]) { 38 low[u] = min(low[u], dfn[v]); 39 } 40 } 41 if (low[u] == dfn[u]) { 42 scc_count++; 43 int v; 44 do { 45 v = S.top(); 46 S.pop(); 47 mark[v] = false; 48 color[v] = scc_count; 49 } while (u != v); 50 } 51 } 52 53 int Indegree[MAXN], Outdegree[MAXN]; 54 55 int main() 56 { 57 int _case, t = 1; 58 scanf("%d", &_case); 59 while (_case--) { 60 scanf("%d %d", &n, &m); 61 NE = 0; 62 memset(head, -1, sizeof(head)); 63 while (m--) { 64 int u, v; 65 scanf("%d %d", &u, &v); 66 Insert(u, v); 67 } 68 cnt = scc_count = 0; 69 memset(dfn, 0, sizeof(dfn)); 70 memset(mark, false, sizeof(mark)); 71 for (int i = 1; i <= n; i++) { 72 if (dfn[i] == 0) Tarjan(i); 73 } 74 memset(Indegree, 0, sizeof(Indegree)); 75 memset(Outdegree, 0, sizeof(Outdegree)); 76 for (int u = 1; u <= n; u++) { 77 for (int i = head[u]; i != -1; i = edge[i].next) { 78 int v = edge[i].v; 79 if (color[u] != color[v]) { 80 Indegree[color[v]]++; 81 Outdegree[color[u]]++; 82 } 83 } 84 } 85 int ans1 = 0, ans2 = 0; 86 for (int i = 1; i <= scc_count; i++) { 87 if (Indegree[i] == 0) ans1++; 88 if (Outdegree[i] == 0) ans2++; 89 } 90 printf("Case %d: ", t++); 91 if (scc_count == 1) { 92 puts("0"); 93 } else 94 printf("%d\n", max(ans1, ans2)); 95 } 96 return 0; 97 } 98 99 100