• 图论:割点


    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
    ",ans);
    49     for(int i=1;i<=n;i++)
    50         if(iscut[i]) printf("%d ",i);
    51     return 0;
    52 }

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

  • 相关阅读:
    449. 序列化和反序列化二叉搜索树
    极客mysql08
    极客mysql06
    MySQL死锁问题(转)
    mysql一些好的问题
    如何在Ubuntu 20.04 LTS Focal Fossa上安装Dokuwiki
    在Ubuntu 20.04 LTS Focal Fossa上安装Icinga
    如何在Ubuntu 20.04 LTS Focal Fossa服务器上安装PowerShell
    如何在CentOS 8服务器上安装Discord
    在CentOS 8服务器上安装Apache Solr搜索平台
  • 原文地址:https://www.cnblogs.com/aininot260/p/9427601.html
Copyright © 2020-2023  润新知