割点&桥模板(割点+桥讲解)

板子:

luogu3388割点

#include 
#include 
#include 
#define N 100005
using namespace std;
struct hh{int x,y;}bri[N];
int tot,point[N],nxt[N*2],v[N*2],nn,dfn[N],low[N],cnt,num;
bool vis[N],iscut[N];
void addline(int x,int y)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void tarjan(int now,int fa)
{
    dfn[now]=low[now]=++nn;
    int size=0;
    for (int i=point[now];i;i=nxt[i])
      if (!dfn[v[i]]) 
        {
            tarjan(v[i],now);
            size++;
            low[now]=min(low[now],low[v[i]]);
            if (low[v[i]]>=dfn[now]) iscut[now]=1;
        }
        else low[now]=min(low[now],dfn[v[i]]);
    if (!fa && size==1) iscut[now]=0; 
}
int main()
{
    int n,m,i;
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addline(x,y);
    } 
    for (i=1;i<=n;i++)
      if (!vis[i]) tarjan(i,0);
    for (i=1;i<=n;i++)
      if (iscut[i]) cnt++;
    printf("%d\n",cnt);
    for (i=1;i<=n;i++)
      if (iscut[i]) printf("%d ",i);
}

POJ3177桥

题解:

其实也是先缩点然后看看剩下的边连接的点,这些边一定是桥,对于一个子图里所有的桥来说,ta们组成的是一棵树

#include 
#include 
#define N 10005
using namespace std;
int tot,nxt[N*2],point[N],v[N*2],dfn[N],nn,low[N],qq,stack[N],num,cnt;
bool vis[N];int x[N],y[N],belong[N],du[N];
void addline(int x,int y)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void tarjan(int x,int fa)
{
    dfn[x]=low[x]=++nn;stack[++num]=x;vis[x]=1;
    bool cf=0;
    for (int i=point[x];i;i=nxt[i])
    {
        if (v[i]==fa && !cf){cf=1;continue;}
        if (!dfn[v[i]])
        {
          tarjan(v[i],x);
          low[x]=min(low[x],low[v[i]]);
        }
        else if (vis[v[i]]) low[x]=min(low[x],dfn[v[i]]);
    }
    if (low[x]==dfn[x])
    {
        cnt++;int now=0;
        while (now!=x)
        {
            now=stack[num--];
            vis[now]=0;
            belong[now]=cnt;
        }
    }  
}
int main()
{
    int n,m,i;
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
        addline(x[i],y[i]);
    }
    for (i=1;i<=n;i++)
      if (!dfn[i]) tarjan(i,0);
    for (i=1;i<=m;i++)  
      if (belong[x[i]]!=belong[y[i]])
        du[belong[x[i]]]++,du[belong[y[i]]]++;
    for (i=1;i<=n;i++)
      if (du[i]==1) qq++;
    printf("%d",(qq+1)/2);
}

普及向:

优秀的学姐(为什么在前几个搜不到啊)

无向图的割点和桥:
割点:一个结点称为割点(或者割顶)当且仅当去掉该节点极其相关的边之后的子图不连通。
:一条边称为桥(或者割边)当且仅当去掉该边之后的子图不连通。

1.割点:

1)当前节点为树根的时候,要有多于一棵子树【特殊处理是因为普通处理翻不到更上面的点,这样如果只有一棵子树的话,也不能成为割点】
2)当前节点u不是树根的时候,条件是“low[v]>=dfn[u]”,也就是在u之后遍历的点,能够向上翻,最多到u。如果能翻到u的上方,那就有环了,去掉u之后,图仍然连通,u不能成为割点。

2.桥:

若是一条无向边(u,v)是桥
当且仅当无向边(u,v)是树枝边的时候,需要满足dfn(u) < low(v),也就是v向上翻不到u及其以上的点,当然不能通过ta从父亲来的那条边啦。

双连通分量

双连通分量有点双连通分量和边双连通分量两种。若一个无向图中的去掉任意一个节点(一条边)都不会改变此图的连通性,即不存在割点(桥),则称作点(边)双连通图。

你可能感兴趣的:(图论)