Luogu2863:利用Tarjan求有向图的强连通分量
强连通分量这这样的一个子图:
图中的任意两点都可以相互通达,它是有向图
这里的例题题意是这样的,统计所有强连通分量中,至少包含两个点的强连通分量的数量
const int maxn=10005; const int maxm=50005; int n,m,cnt,deep,top,sum,ans; int g[maxn],vis[maxn],dfn[maxn<<1],low[maxn<<1],st[maxn<<1],col[maxn],tot[maxn]; struct Edge{int t,next;}e[maxm];
这里面把强连通分量的点放在st栈里,用vis进行存在性标记
col的意思是下标属于哪一个强连通分量,tot是用来统计每一种强连通分量所包含的顶点数量的
void tarjan(int u) { dfn[u]=++deep;low[u]=deep; vis[u]=1; st[++top]=u; for(int tmp=g[u];tmp;tmp=e[tmp].next) { int v=e[tmp].t; if(!dfn[v]) {tarjan(v);low[u]=min(low[u],low[v]);} else if(vis[v]) low[u]=min(low[u],low[v]); } if(dfn[u]==low[u]) { col[u]=++sum;vis[u]=0; while(st[top]!=u) { col[st[top]]=sum; vis[st[top--]]=0; } top--; } }
这里的Tarjan还是很显然的,与之前的两种大同小异
最后给出完整的实现:
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=10005; 5 const int maxm=50005; 6 int n,m,cnt,deep,top,sum,ans; 7 int g[maxn],vis[maxn],dfn[maxn<<1],low[maxn<<1],st[maxn<<1],col[maxn],tot[maxn]; 8 struct Edge{int t,next;}e[maxm]; 9 void addedge(int u,int v) 10 { 11 e[++cnt].t=v; 12 e[cnt].next=g[u];g[u]=cnt; 13 } 14 void tarjan(int u) 15 { 16 dfn[u]=++deep;low[u]=deep; 17 vis[u]=1; 18 st[++top]=u; 19 for(int tmp=g[u];tmp;tmp=e[tmp].next) 20 { 21 int v=e[tmp].t; 22 if(!dfn[v]) {tarjan(v);low[u]=min(low[u],low[v]);} 23 else if(vis[v]) low[u]=min(low[u],low[v]); 24 } 25 if(dfn[u]==low[u]) 26 { 27 col[u]=++sum;vis[u]=0; 28 while(st[top]!=u) 29 { 30 col[st[top]]=sum; 31 vis[st[top--]]=0; 32 } 33 top--; 34 } 35 } 36 int main() 37 { 38 scanf("%d%d",&n,&m); 39 int u,v; 40 for(int i=1;i<=m;i++) 41 { 42 scanf("%d%d",&u,&v); 43 addedge(u,v); 44 } 45 for(int i=1;i<=n;i++) 46 if(!dfn[i]) tarjan(i); 47 for(int i=1;i<=n;i++) tot[col[i]]++; 48 for(int i=1;i<=sum;i++) 49 if(tot[i]>1) ans++; 50 printf("%d ",ans); 51 return 0; 52 }