Luogu 2812 校园网络 - Tarjan
Description
给出一个有向图, 要求出至少从哪几个点出发, 能不漏地经过所有节点。
再求出至少加几条边, 才能使图变成一个强联通分量
Solution
求出所有强联通分量, 形成一个有向无环图, 第一问题就是求出有多少强联通分量的入度为 $0$
第二个问题就是求出 入度为$0 $和 出度为$0$ 的强联通分量的数量 的 最大值, 想象一下就可以了。
在整个图都是强联通分量下, 第二个问题答案为 $0$。
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rd read() 5 #define rep(i,a,b) for(int i = (a); i <= (b); ++i) 6 #define per(i,a,b) for(int i = (a); i >= (b); --i) 7 using namespace std; 8 9 const int N = 10500; 10 const int M = 6e6; 11 12 int head[N], tot; 13 int col[N], col_num, size[N]; 14 int n, dfn[N], low[N], cnt, vis[N]; 15 int st[N], tp, ans1, ans2; 16 int chu[N], ru[N]; 17 18 struct edge { 19 int nxt, to, fr; 20 }e[M]; 21 22 int read() { 23 int X = 0, p = 1; char c = getchar(); 24 for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 25 for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 26 return X * p; 27 } 28 29 void add(int u, int v) { 30 e[++tot].to = v; 31 e[tot].nxt = head[u]; 32 e[tot].fr = u; 33 head[u] = tot; 34 } 35 36 void tarjan(int u) { 37 dfn[u] = low[u] = ++cnt; 38 st[++tp] = u; 39 vis[u] = 1; 40 for(int i = head[u]; i; i = e[i].nxt) { 41 int nt = e[i].to; 42 if(!dfn[nt]) tarjan(nt), low[u] = min(low[u], low[nt]); 43 else if(vis[nt]) low[u] = min(low[u], dfn[nt]); 44 } 45 if(dfn[u] == low[u]) { 46 col_num++; 47 for(; tp;) { 48 int nt = st[tp--]; 49 vis[nt] = 0; 50 col[nt] = col_num; 51 if(nt == u) break; 52 } 53 } 54 } 55 56 int main() 57 { 58 n = rd; 59 for(int i = 1; i <= n; ++i) { 60 for(; ;) { 61 int x = rd; 62 if(!x) break; 63 add(i, x); 64 } 65 } 66 for(int i = 1; i <= n; ++i) 67 if(!dfn[i]) tarjan(i); 68 for(int i = 1; i <= tot; ++i) { 69 int x = e[i].fr, y = e[i].to; 70 if(col[x] == col[y]) continue; 71 ru[col[y]]++; chu[col[x]]++; 72 } 73 for(int i = 1; i <= col_num; ++i) 74 if(!ru[i]) ans1++; 75 printf("%d\n", ans1); 76 if(col_num == 1) return printf("0\n"), 0; 77 for(int i = 1; i <= col_num; ++i) 78 if(!chu[i]) ans2++; 79 printf("%d\n", max(ans1, ans2)); 80 }