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

来源:互联网 发布:淘宝品类销售排行榜 编辑:程序博客网 时间:2024/06/02 05:34

板子:

luogu3388割点

#include <cstdio>#include <cstring>#include <iostream>#define N 100005using 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 <cstdio>#include <iostream>#define N 10005using 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从父亲来的那条边啦。

双连通分量

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

原创粉丝点击