強連通割點割橋模板
阿新 • • 發佈:2018-12-07
//如果u是根節點,只要它有兩個子節點就說明是割點, //否則,滿足(u,v)為樹枝邊(或稱父子邊,即u是v的父親),使得dfn[u]<=low[v]; //橋無向邊(u,v),當且僅當(u,v)為樹枝邊,且滿足dfn[u]<low[v]; #include<cstring> #include<string> #include<cstdio> #include<stdlib.h> #include<iostream> #include<algorithm> #include<math.h> #include<map> #include<vector> #include<stack> #define inf 0x3f3f3f3f #include<queue> #include<set> using namespace std; typedef long long ll; const int N=1e5+5; const int M=1e6+5; struct node { int v,ne; }edge[M]; int head[N],dfn[N],low[N]; int iscut[N];//割點標記 int n,top,e; int cut; stack<int>sta; struct Brige { int u,v; }brige[M]; void init() { memset(head,-1,sizeof(head)); e=0;cut=0; } void add(int a,int b) { edge[e].v=b; edge[e].ne=head[a]; head[a]=e++; } void tarjan(int now,int pre) { low[now]=dfn[now]=++top; int son=0; for(int i=head[now];i!=-1;i=edge[i].ne) { int v=edge[i].v; if(v==pre) continue; if(!dfn[v]) { son++;//孩子節點的數目 tarjan(v,now); low[now]=min(low[now],low[v]);//用後代更新low if(low[v]>=dfn[now])//判斷是否為割點 iscut[now]=1; if(dfn[now]<low[v])//判斷是否為割橋 { brige[cut].u=min(v,now); brige[cut++].v=max(now,v); } } else//如果v已被訪問,說明(u,v)室反向邊,用反向邊更新low low[now]=min(low[now],dfn[v]); } if(pre==-1&&son==1)//只有一個孩子節點(割點判斷,求割橋試不需要這裡) iscut[now]=0; } void solve() { top=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(iscut,0,sizeof(iscut)); for(int i=0;i<n;i++) { if(!dfn[i]) tarjan(i,-1); } } int main() { while(~scanf("%d",&n)) { int sum,a,b; init(); for(int i=0;i<n;i++) { scanf("%d (%d)",&a,&sum); for(int j=0;j<sum;j++) { scanf("%d",&b); add(a,b); } } solve(); } return 0; }