Luogu P2863 [USACO06JAN]The Cow Prom S
阿新 • • 發佈:2020-07-26
思路
這個題就是純正的Tarjan模板題,關於難以理解的、玄學的low陣列,建議感性理解。網上的解釋千姿百態,啥樣的都有,有的對有的錯,看多了反而會暈。所以建議Tarjan模板基本的幾個部分多打幾遍,
熟練了就好(不建議強求理解)。
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define MAXN 20010 #define MAXM 50010 int n, m, idx; int head[MAXM], cnt; int dfn[MAXN], low[MAXN]; int stk[MAXN], top, size[MAXN]; int flag[MAXN], bel[MAXN], scc; struct node{ int nxt, to; } edge[MAXM]; inline int read(void){ int f = 1, x = 0;char ch; do{ch = getchar();if(ch=='-')f = -1;} while (ch < '0' || ch > '9'); do{ x = x * 10 + ch - '0';ch = getchar();} while (ch >= '0' && ch <= '9'); return f * x; } inline int _min(int x,int y){ return x < y ? x : y; } inline void add_edge(int x,int y){ ++cnt; edge[cnt].nxt = head[x]; edge[cnt].to = y; head[x] = cnt; return; } void tarjan(int k){ dfn[k] = low[k] = ++idx; stk[++top] = k; flag[k] = 1; for (int i = head[k]; i; i = edge[i].nxt){ int v = edge[i].to; if(!dfn[v]) tarjan(v), low[k] = _min(low[k], low[v]); else if(flag[v]) low[k] = _min(low[k], dfn[v]);//這幾個min程式碼量也不大,建議背誦(大部分Tarjan題都不會對這兩個min做出變動) } if(dfn[k]==low[k]){ int now = -1; ++scc; while(now!=k){ now = stk[top], --top; flag[now] = 0; ++size[scc]; bel[now] = scc; }//每次找到返祖邊(環)後統計答案 } } int main(){ n = read(), m = read(); for (int i = 1; i <= m; ++i){ int u = read(), v = read(); add_edge(u, v);//連有向邊 } for (int i = 1; i <= n; ++i) if(!dfn[i]) tarjan(i);//注意原圖可能不連通 // for (int i = 1; i <= n; ++i){ // printf("dfn[%d]=%d,low[%d]=%d\n", i, dfn[i], i, low[i]); // } int ans = 0; for (int i = 1; i <= scc; ++i) if(size[i]>1) ++ans;//統計大小大於1的強連通分量個數 printf("%d\n", ans); return 0; }