tarjan求割点
首先给大家一个网址讲的比较细:http://www.cnblogs.com/en-heng/p/4002658.html
如果还有不懂的话,可以回来再看看我的文章;
概念明确:
low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点
用那个网址的例子,我给大家推演一下tarjan的dfn和low;
A的dfn和low均为1;
B:low = 1(通过B->A的回边)
C: low = 1(通过C->A的回边)
D:low = (B的dfn)5,(通过D->B的回边)
E:low = 5,(通过E->B的回边)
F:low = 1(通过F->A的回边)
G:low = 5(通过G->B的回边)
H:low = 5(通过H->B的回边)
例题可以参考cojs921
http://cojs.tk/cogs/problem/problem.php?pid=921
代码如下
#include<cstdio> const int maxn = 5010 ; using namespace std; inline void read(int &x){ x=0;char ch; while(ch=getchar(),ch<'!'); while(x=10*x+ch-'0',ch=getchar(),ch>'!'); } inline int cat_max(const int &a,const int &b){return a>b ? a:b;} inline int cat_min(const int &a,const int &b){return a<b ? a:b;} struct Edge{ int to,next; }G[100100]; int tot,head[maxn],scc_cnt,dfs_cnt; int dfn[maxn],low[maxn],sccno[maxn]; int sta[maxn],top,num[maxn]; void add(int u,int v){ G[++tot].to=v; G[tot].next=head[u]; head[u]=tot; } void tarjan(int u){ low[u]=dfn[u]=++dfs_cnt; sta[++top]=u; for(int i=head[u];i;i=G[i].next){ int to=G[i].to; if(!dfn[to]){ tarjan(to); low[u]=cat_min(low[u],low[to]); } else if(!sccno[to]) low[u]=cat_min(low[u],dfn[to]); } if(low[u]==dfn[u]){ scc_cnt++; while(1){ int x=sta[top--]; sccno[x]=scc_cnt; num[scc_cnt]++; if(x==u) break; } } } int main(){ freopen("classroom.in","r",stdin); freopen("classroom.out","w",stdout); int n;read(n); int m;read(m); int x,y,op; for(int i=1;i<=m;i++){ read(x),read(y),read(op); add(x,y); if(op==2) add(y,x); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); int max1=0,pos=0; for(int i=1;i<=scc_cnt;i++){ if(num[i]>max1){ max1=num[i]; pos=i; } } printf("%d\n",max1); for(int i=1;i<=n;i++){ if(sccno[i]==pos){ printf("%d ",i); } } fclose(stdin);fclose(stdout); return 0; }
人就像命运下的蝼蚁,谁也无法操控自己的人生.