今天学了一个强连通分量,用tarjan做。北京之前讲过,今天讲完和之前一样,没有什么进步。上课没听讲,只好回来搞,这里安利一个博客:链接
https://blog.csdn.net/qq_34374664/article/details/77488976
讲一下我自己的体会吧,其实就是维护一个栈,然后树上跑dfs,每个节点存两个值:dn和low,dn代表dfs的顺序(时间),low代表的是他可以连通的最小的节点。
模拟一下,然后就会发现,其实整个算法就是模拟了一下将每个点压入栈。然后遇到之前在栈里的元素,向后弹出到这一位就行了。
洛谷板子题:链接
直接上代码,很好懂。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int m,n,len = 0,stc[50050]; int ri = 0,tot = 0,ans = 0; int num[50005]; struct node{ int l,r,nxt; }a[50050]; int low[50050],lst[50050]; int dn[50080]; int chu[50050]; bool vis[50050]; int add(int x,int y) { a[++len].l = x; a[len].r = y; a[len].nxt = lst[x]; lst[x] = len; chu[x]++; } void dfs(int x) { dn[x] = low[x] = ++tot; stc[++ri] = x; vis[x] = 1; for(int k = lst[x];k;k = a[k].nxt) { int y = a[k].r; if(!dn[y]) { dfs(y); low[x] = min(low[x],low[y]); } else if(vis[y]) { low[x] = min(low[x],dn[y]); } } if(low[x] == dn[x]) { ans ++; int v; do { num[ans]++; vis[stc[ri]] = 0; v = stc[ri--]; } while(x != v); } } int main() { memset(vis,0,sizeof(vis)); scanf("%d%d",&n,&m); int x,y; for(int i = 1;i <= m;i++) { scanf("%d%d",&x,&y); add(x,y); } for(int i = 1;i <= n;i++) if(dn[i] == 0) { dfs(i); } // cout<<ans<<endl; tot = 0; for(int i = 1;i <= ans;i++) { if(num[i] > 1) { tot++; } } printf("%d\n",tot); return 0; }
原文地址:https://www.cnblogs.com/DukeLv/p/9383780.html
时间: 2024-10-01 08:04:37