Tarjan 割点 割边 缩点 SCC🤪
// 不错的博客眼👁 (本文中的图片来源地)
// 割点 UVA 315
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 * @Promlem: 3 * @Time Limit: ms 4 * @Memory Limit: k 5 * @Author: pupil-XJ 6 * @Date: 2019-10-30 23:24:12 7 * @LastEditTime: 2019-10-31 01:45:55 8 */ 9 #include<cstdio> 10 #include<cstring> 11 #include<iostream> 12 #include<algorithm> 13 #include<set> 14 #define rep(i, n) for(int i=0;i!=n;++i) 15 #define rep1(i, n) for(int i=1;i<=n;++i) 16 using namespace std; 17 // ----------------------------------------------------- 18 const int MAXN = 100+5; 19 const int MAXM = MAXN*MAXN; 20 21 int num; 22 int head[MAXN]; 23 struct node { 24 int v, next; 25 } edge[MAXM]; 26 27 inline void add(int x, int y) { 28 edge[num].v = y; 29 edge[num].next = head[x]; 30 head[x] = num++; 31 } 32 33 int n; 34 int cnt; 35 int dfn[MAXN], low[MAXN]; 36 set<int> disct; 37 38 void Tarjan(int cur, int root) { 39 dfn[cur] = low[cur] = ++cnt; 40 int flag = 0; 41 for(int i = head[cur]; i != -1; i = edge[i].next) { 42 int v = edge[i].v; 43 if(!dfn[v]) { 44 Tarjan(v, root); 45 low[cur] = min(low[cur], low[v]); 46 if(low[v] >= dfn[cur]) { 47 ++flag; 48 if(cur != root || flag > 1) disct.insert(cur); 49 } 50 } 51 else low[cur] = min(low[cur], dfn[v]); 52 } 53 } 54 55 void solve() { 56 cnt = 0; 57 disct.clear(); 58 rep1(i, n) dfn[i] = low[i] = 0; 59 rep1(i, n) if(!dfn[i]) Tarjan(i, i); 60 cout << disct.size() << "\n"; 61 } 62 63 int main() { 64 while(cin >> n && n) { 65 num = 0; 66 rep1(i, n) head[i] = -1; 67 int u, v; 68 while(cin >> u && u) { 69 while(getchar() != '\n') { 70 cin >> v; 71 add(u, v); add(v, u); 72 } 73 } 74 solve(); 75 } 76 return 0; 77 }
// 割边 UVA 796
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 * @Promlem: 3 * @Time Limit: ms 4 * @Memory Limit: k 5 * @Author: pupil-XJ 6 * @Date: 2019-10-31 01:44:42 7 * @LastEditTime: 2019-10-31 11:34:30 8 */ 9 #include<cstdio> 10 #include<algorithm> 11 #include<vector> 12 #define rep(i, n) for(int i=0;i!=n;++i) 13 #define rep1(i, n) for(int i=1;i<=n;++i) 14 using namespace std; 15 const int MAXN = 1000+5; 16 const int MAXM = MAXN*MAXN; 17 typedef pair<int,int> Pair; 18 19 int num; 20 int head[MAXN]; 21 struct node { 22 int v, next; 23 } edge[MAXM]; 24 25 inline void add(int x, int y) { 26 edge[num].v = y; 27 edge[num].next = head[x]; 28 head[x] = num++; 29 } 30 31 int cnt; 32 int dfn[MAXN], low[MAXN]; 33 bool bridge[MAXM]; 34 void Tarjan(int cur, int edge_num) { 35 dfn[cur] = low[cur] = ++cnt; 36 for(int i = head[cur]; i != -1; i = edge[i].next) { 37 int v = edge[i].v; 38 if(!dfn[v]) { 39 Tarjan(v, i); 40 low[cur] = min(low[cur], low[v]); 41 if(low[v] > dfn[cur]) bridge[i] = bridge[i^1] = true; 42 } 43 else if(i != (edge_num^1)) low[cur] = min(low[cur], dfn[v]); 44 } 45 } 46 47 int n; 48 vector<Pair> ans; 49 50 void solve() { 51 cnt = 0; 52 ans.clear(); 53 rep(i, num) bridge[i] = false; 54 rep(i, n) dfn[i] = 0; 55 rep(i, n) if(!dfn[i]) Tarjan(i, 0); 56 for(int i = 0; i != num; i += 2) { 57 if(bridge[i]) { 58 if(edge[i].v > edge[i^1].v) ans.push_back(make_pair(edge[i^1].v, edge[i].v)); 59 else ans.push_back(make_pair(edge[i].v, edge[i^1].v)); 60 } 61 } 62 sort(ans.begin(), ans.end()); 63 printf("%d critical links\n",ans.size()); 64 rep(i, ans.size()) { 65 printf("%d - %d\n",ans[i].first,ans[i].second); 66 } 67 printf("\n"); 68 } 69 70 int main() { 71 while(scanf("%d", &n) == 1) { 72 num = 0; 73 rep(i, n) head[i] = -1; 74 int u, v, nm; 75 rep(i, n) { 76 scanf("%d (%d)", &u, &nm); 77 rep(j, nm) { 78 scanf("%d", &v); 79 if(u < v) add(u, v), add(v, u); 80 } 81 } 82 solve(); 83 } 84 return 0; 85 }
// 缩点 poj 2186
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int MAXN = 10000+5; 7 const int MAXM = 50000+5; 8 9 struct node { 10 int v, next; 11 } edge[MAXM]; 12 int num; 13 14 int head[MAXN]; 15 16 inline void add_edge(int x, int y) { 17 edge[num].v = y; 18 edge[num].next = head[x]; 19 head[x] = num++; 20 } 21 22 int cnt, t, scc_cnt; 23 int dfn[MAXN], low[MAXN], vis[MAXN], sccno[MAXN], stack[MAXN]; 24 int scc_num[MAXN], out[MAXN]; 25 26 inline void Tarjan(int cur) { 27 dfn[cur] = low[cur] = ++cnt; 28 stack[t++] = cur; 29 for(int i = head[cur]; i != -1; i = edge[i].next) { 30 if(!dfn[edge[i].v]) { 31 Tarjan(edge[i].v); 32 low[cur] = min(low[cur], low[edge[i].v]); 33 } 34 else if(vis[edge[i].v]) { 35 low[cur] = min(low[cur], dfn[edge[i].v]); 36 } 37 } 38 if(dfn[cur] == low[cur]) { 39 ++scc_cnt; 40 int v; 41 do { 42 v = stack[--t]; 43 sccno[v] = scc_cnt; 44 ++scc_num[scc_cnt]; 45 vis[v] = 0; 46 } while(v != cur); 47 } 48 } 49 50 int main() { 51 int n, m; 52 scanf("%d%d", &n, &m); 53 memset(head, -1, sizeof(head)); 54 int x, y; 55 for(int i = 0; i != m; ++i) { 56 scanf("%d%d", &x, &y); 57 add_edge(x, y); 58 } 59 for(int i = 1; i <= n; ++i) { 60 if(!dfn[i]) Tarjan(i); 61 } 62 for(int i = 1; i <= n; ++i) { 63 for(int j = head[i]; j != -1; j = edge[j].next) { 64 int a = sccno[i], b = sccno[edge[j].v]; 65 if(a != b) ++out[sccno[i]]; 66 } 67 } 68 int ans = 0; 69 int flag; 70 for(int i = 1; i <= scc_cnt; ++i) { 71 if(!out[i]) { 72 ++ans; 73 flag = i; 74 } 75 } 76 if(ans == 1) printf("%d\n", scc_num[flag]); 77 else printf("0\n"); 78 return 0; 79 }
// SCC
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<stack> 4 using namespace std; 5 6 const int MAXN = 1000+5; 7 8 struct node { 9 int v, next; 10 } edge[2*MAXN]; 11 int num; 12 13 int head[2*MAXN]; 14 int dfn[MAXN], low[MAXN], sccno[MAXN], vis[MAXN]; 15 stack<int> sk; 16 int cnt, scc_cnt; 17 18 void add_edge(int x, int y) { 19 edge[num].v = y; 20 edge[num].next = head[x]; 21 head[x] = num++; 22 } 23 24 void tarjan(int cur) { 25 dfn[cur] = low[cur] = ++cnt;// dfn给结点设定次序 low初始化(u及其后代能追溯到的最早-最先被发现 祖先点v的dfn[v]值) 26 sk.push(cur); 27 for(int i = head[cur]; i != -1; i = edge[i].next) { 28 if(!dfn[edge[i].v]) { 29 tarjan(edge[i].v); 30 low[cur] = min(low[cur], low[edge[i].v]); 31 } 32 else if(vis[edge[i].v]) { 33 low[cur] = min(low[cur], dfn[edge[i].v]); 34 } 35 } 36 if(dfn[cur] == low[cur]) { 37 ++scc_cnt; 38 for(;;) { 39 int x = sk.top(); sk.pop(); 40 sccno[x] = scc_cnt; 41 vis[x] = 0; 42 printf("%d ", x); 43 if(x == cur) break; 44 } 45 printf("\n"); 46 } 47 } 48 49 int main() { 50 memset(head, -1, sizeof(head));54 num = 0; 51 cnt = 0; 52 scc_cnt = 0; 53 54 int n, m; // n个点 m条边 55 scanf("%d%d", &n, &m); 56 int s, e; 57 for(int i = 0; i != m; ++i) { 58 scanf("%d%d", &s, &e); 59 add_edge(s, e); 60 } 61 for(int i = 1; i <= n; ++i) { 62 if(!dfn[i]) tarjan(i); 63 } 64 return 0; 65 } 66 input: 67 8 68 3 69 2 70 4 71 4 72 5 73 6 74 1 75 6 76 output: 77 5 78 4 2 1