loj 1210 (求最少的加边数使得图变成强连通)

题目链接:http://lightoj.com/volume_showproblem.php?problem=1210

思路:首先是缩点染色,然后重建并且统计新图中的每个点的入度和出度,于是答案就是max(入度为0的点的个数, 出度为0的点的个数,这里有一个trick就是如果scc_count == 1,那么应该输出0.

  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
", max(ans1, ans2));
 95     }
 96     return 0;
 97 }
 98 
 99 
100         
View Code
原文地址:https://www.cnblogs.com/wally/p/3529842.html