1. 程式人生 > >強連通割點割橋模板

強連通割點割橋模板

 
//如果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;
}