Luogu3388:利用Tarjan求无向图的割点

割点就是维护双连通分量的一个点,如果删去的话,原本的双连通分量就会被拆成若干个连通分量

利用Tarjan算法可以求出无向图的所有割点

下面介绍一下:

int n,m,cnt,deep,root,ans;
int g[maxn],dfn[maxn],low[maxn],iscut[maxn];
struct Edge{int t,w,next;}e[maxm];

邻接表建图,开二倍边长(无向图)

deep用来跟踪记录每一个点的深度,或者说,它在dfs中是第几个访问的

然后root是用来给当前进行dfs的连通分量指定的一个根

dfn数组用来记录当前点在dfs中是第几个被搜到的,low数组用来记录这个点及其子孙节点所连的所有节点中,dfn的最小值

由于本题不用求强连通分量,不用开栈记录了

iscut的意思很显然

    for(int i=1;i<=n;i++)
        if(!dfn[i]) {root=i;tarjan(i,-1);}

建图后对于每一个连通分量,进行一次Tarjan求割点

Tarjan算法如下:

int tarjan(int u,int fa)
{
    int child=0,lowu;
    lowu=dfn[u]=++deep;
    for(int tmp=g[u];tmp;tmp=e[tmp].next)
    {
        int v=e[tmp].t;
        if(!dfn[v])
        {
            child++;
            int lowv=tarjan(v,u);
            lowu=min(lowu,lowv);
            if(lowv>dfn[u]) iscut[u]=1;
        }
        else if(v!=fa&&dfn[v]<dfn[u])
            lowu=min(lowu,dfn[v]);
    }
    if(fa<0&&child==1) iscut[u]=false;
    low[u]=lowu;
    return lowu;
}

具体原理和求强连通的Tarjan很类似(其实Tarjan就是一类东西。。。)

先不介绍了以后再说

下面给出完整的实现,题是洛谷上的一个板子题,然后我再洛谷上发现了不少神奇的板子,真是贴心

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=100005;
 5 const int maxm=200005;
 6 int n,m,cnt,deep,root,ans;
 7 int g[maxn],dfn[maxn],low[maxn],iscut[maxn];
 8 struct Edge{int t,w,next;}e[maxm];
 9 void addedge(int u,int v,int w)
10 {
11     e[++cnt].t=v;e[cnt].w=w;
12     e[cnt].next=g[u];g[u]=cnt;
13 }
14 int tarjan(int u,int fa)
15 {
16     int child=0,lowu;
17     lowu=dfn[u]=++deep;
18     for(int tmp=g[u];tmp;tmp=e[tmp].next)
19     {
20         int v=e[tmp].t;
21         if(!dfn[v])
22         {
23             child++;
24             int lowv=tarjan(v,u);
25             lowu=min(lowu,lowv);
26             if(lowv>dfn[u]) iscut[u]=1;
27         }
28         else if(v!=fa&&dfn[v]<dfn[u])
29             lowu=min(lowu,dfn[v]);
30     }
31     if(fa<0&&child==1) iscut[u]=false;
32     low[u]=lowu;
33     return lowu;
34 }
35 int main()
36 {
37     scanf("%d%d",&n,&m);
38     int u,v;
39     for(int i=1;i<=m;i++)
40     {
41         scanf("%d%d",&u,&v);
42         addedge(u,v,1);addedge(v,u,1);
43     }
44     for(int i=1;i<=n;i++)
45         if(!dfn[i]) {root=i;tarjan(i,-1);}
46     for(int i=1;i<=n;i++)
47         if(iscut[i]) ans++;
48     printf("%d\n",ans);
49     for(int i=1;i<=n;i++)
50         if(iscut[i]) printf("%d ",i);
51     return 0;
52 }

目前的程度,先能调用API就够了

猜你喜欢

转载自www.cnblogs.com/aininot260/p/9427601.html
今日推荐