割点、桥模板以及点双连通、边双连通

一、概念

概念:

1.桥: 如果在图G中删去一条边e后,图G的连通分支数增加,即W(G-e)>W(G),则称边u为G的桥,又称割边或关节边。

2.割点:如果在图G中删去一个结点u后,图G的连通分枝数增加,即W(G-u)>W(G),则称结点u为G的割点,又称关节点。

3.点双连通分量:不含割点的连通子图

4.边双连通分量:不含割边的连通子图

性质:

1.边双连通分量中,任意两点都在某个边环中。(任意两点不一定在点环中)

2.点双连通分量中,任意两点都在某个点环中。

3.点双连通分量不一定是边双连通分量,边双连通分量不一定是点双连通分量。

二、求桥模板

#define N 100100
#define M 200110

#define INF 0x3fffffff

struct node
{
    int from,to,next;
}edge[2*M];

vector<int>mat[N];//用来建新图.

int n,m;
int savex[M],savey[M];
int cnt,pre[N];
bool mark[2*M];
bool save[2*M];
int low[N];
int mylink[N];

void add_edge(int u,int v)
{
    edge[cnt].to=v;
    edge[cnt].from=u;
    edge[cnt].next=pre[u];
    pre[u]=cnt++;
}

void dfs(int s,int num)//寻找桥
{
    low[s] = num;
    int mi=num;
    for(int p=pre[s];p!=-1;p=edge[p].next)
    {
        int v=edge[p].to;
        if(mark[p]==1) continue;
        if(low[v]==-1)
        {
            mark[p]=1;
            mark[p^1]=1;
            dfs(v,num+1);
            if(low[v]>num) // 说明edge[p]是桥
            {
                save[p]=1;
                save[p^1]=1;
            }
        }
        mi=min(mi,low[v]);
    }
    low[s]=mi;
}

void dfs1(int s,int num)//缩点
{
    mylink[s]=num;
    mark[s]=1;
    for(int p=pre[s];p!=-1;p=edge[p].next)
    {
        int v=edge[p].to;
        if(mark[v]==1||save[p]==1) continue;
        dfs1(v,num);
    }
}

void init()
{
    cnt=0;
    memset(pre,-1,sizeof(pre));
}

int main()
{
    init();
    //构图
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);

        savex[i] = x;
        savey[i] = y;
        add_edge(x,y);
        add_edge(y,x);
    }

    //tarjan 找桥。 save里面记录了边是否是桥的信息
    memset(low,-1,sizeof(low));
    memset(mark,0,sizeof(mark));
    memset(save,0,sizeof(save));

    for(int i=1;i<=n;i++)
    {
        if(low[i]==-1)
            dfs(i,0);
    }

    //缩点
    memset(mark,0,sizeof(mark));
    int id=0;
    for(int i=1;i<=n;i++)
    {
        if(mark[i]==0)
        {
            dfs1(i,++id);//这里面还要处理
        }
    }

    //每个点对应一个mylink,下列操作构建新图。
    for(int i=0;i<m;i++)
    {
        mat[ mylink[ savex[i] ] ].push_back(mylink[ savey[i] ]);
        mat[ mylink[ savey[i] ] ].push_back(mylink[ savex[i] ]);
    }

    return 0;
}

找到桥后,除去桥后的图中连通块即为边双连通分量。

三、割点模板

#define N 110
#define M N*N

struct node
{
    int to,next;
}edge[2*M];

int n;//图中节点个数,边的个数
int pre[N],cnt;
bool cutmark[N];
int vis[N];
int indx;
int mylink[N];
int tn;

void init()
{
    memset(pre,-1,sizeof(pre));
    cnt = 0;
}

void add_edge(int u,int v)//向图中插入一条无向边
{
    edge[cnt].to = v;
    edge[cnt].next = pre[u];
    pre[u] = cnt++;
    edge[cnt].to = u;
    edge[cnt].next = pre[v];
    pre[v] = cnt++;
}

void build_map()//构图
{
    init();
    //然后就是加边
//    char str[10010];
//    getchar();
//    while(gets(str) && str[0]!=‘0‘)
//    {
//        stringstream in(str);
//        int tmp;
//        int tu=0;
//        int flag=0;
//        while(in>>tmp)
//        {
//            if(flag == 0)
//            {
//                flag = 1;
//                tu = tmp;
//            }
//            else
//            {
//                add_edge(tu,tmp);
//            }
//        }
//    }

}

void dfs(int s,int fa,bool sign)//寻找割点
{
    vis[s] = ++indx;
    int _mi = indx;//这个结点所能到达的最上层
    int _cutedge = 0;
    for (int p=pre[s]; p!=-1; p=edge[p].next) {
        int _v = edge[p].to;
        if(_v == fa) continue;
        if(vis[_v] == -1)
        {
            dfs(_v,s,sign|1);
            if(vis[_v] >= vis[s])
            {
                _cutedge ++;
            }
        }
        _mi = min(_mi,vis[_v]);
    }
    vis[s] = _mi;
    if( (sign == 0&&_cutedge>1)||(sign == 1&&_cutedge>0) )
    {
        cutmark[s] = 1;//为割点
    }
}

void find_cutnode()
{
    memset(cutmark,0,sizeof(cutmark));
    memset(vis,-1,sizeof(vis));
    indx = 0;
    for(int i=1;i<=n;i++)
    {
        if(vis[i] == -1)
        {
            dfs(i,-1,0);
        }
    }
    //是否为割点,存在cutmark中
}

void dfs1(int s,int _id)//缩点用DFS
{
    mylink[s] = _id;
    for(int p=pre[s];p!=-1;p=edge[p].next)
    {
        int _v = edge[p].to;
        if(mylink[_v] == 0 && cutmark[_v] == 0)
        {
            dfs1(_v,_id);
        }
    }
}

void shuodian()//缩点,对应为[1-tn]中的点
{
    tn = 0;
    memset(mylink,0,sizeof(mylink));
    for(int i=1;i<=n;i++)
    {
        if(mylink[i] == 0 && cutmark[i] == 0)
        {
            dfs1(i,++tn);
        }
    }
    //然后把割点也算成一个点双连通块
    for(int i=1;i<=n;i++)
    {
        if(cutmark[i] == 1)
        {
            mylink[i] = ++tn;
        }
    }
    //tn 表示点双连通块的个数.
}

同理,除去割点后,剩余图中的连通块即为点双连通分量。

时间: 2024-11-25 11:51:54

割点、桥模板以及点双连通、边双连通的相关文章

连通分量模板:tarjan: 求割点 &amp;&amp; 桥 &amp;&amp; 缩点 &amp;&amp; 强连通分量 &amp;&amp; 双连通分量 &amp;&amp; LCA(最近公共祖先)

PS:摘自一不知名的来自大神. 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最

(转)Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

本文转载自:http://hi.baidu.com/lydrainbowcat/item/f8a5ac223e092b52c28d591c 作者提示:在阅读本文之前,请确保您已经理解并掌握了基本的Tarjan算法,不会的请到http://hi.baidu.com/lydrainbowcat/blog/item/42a6862489c98820c89559f3.html阅读.   基本概念:   1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如

Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】

基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最小割边集合中的边数.

割点 桥 双连通分量模版

求割点和点双连通分量 const int maxn = 1010; vector <int> a[maxn], bcc[maxn]; int pre[maxn]; int low[maxn]; bool iscut[maxn]; int bccno[maxn]; int cnt[maxn]; int dfs_clock; int bcc_cnt; int n; struct Edge { int u, v; }; stack <Edge> S; int dfs(int u, int

HDU 4738 --Caocao&#39;s Bridges 【无向图边双联通 &amp;&amp; 求权值最小的桥 &amp;&amp; 模板】

Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2641    Accepted Submission(s): 855 Problem Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. B

割点算法模板(Cut-vertex)

下面是求割點的模板,還有cut_vertex_num[]數組(array)記錄了哪些是割點 Int cut_vertex_num[]; void dfs(int cur,int pa) { int child=0,flag=0,i; low[cur]=dfn[cur]=++depth; for(i=0;i<adj[cur].size();i++) { int next=adj[cur][i]; if(!dfn[next]) //若未访问过 { child++; dfs(next,cur); lo

双连通分量(点-双连通分量&amp;边-双连通分量)

概念: 双连通分量有点双连通分量和边双连通分量两种.若一个无向图中的去掉任意一个节点(一条边)都不会改变此图的连通性,即不存在割点(桥),则称作点(边)双连通图. 一个无向图中的每一个极大点(边)双连通子图称作此无向图的点(边)双连通分量.求双连通分量可用Tarjan算法.--百度百科 Tip:先学一下tarjan算法以及求割点割边的算法之后,再看会比较好理解一些. 点双连通和边双连通 连通的概念:在无向图中,所有点能互相到达 连通分量:互相联通的子图 点双连通:删掉一个点之后,图仍联通 边双连

单引号中有双引号,双引号还需要引号怎么办

单引号中有双引号,双引号还需要引号怎么办     今天,我在做一个日历控件时,发现在拼接HTML中的input时,出现引号里还有引号:     '<input type="button" onclick="findSearch("MU")"'/>     结果,火狐浏览器出现"死机"现象.     将findSearch中的双引号改为单引号,结果出现报错提示:     后来将findSearch中的双引号利用转义字

Win10双网不双待攻略

声明:本文与个人的技术兴趣毫无关系,只是因为有迫不得已的实际需求,才不得不想办法.问题解决了,那就做个笔记吧,万一有别的同学也有类似的需求呢.所谓"艰难困苦,玉汝于成",大概就是这个道理.(PS:标题我没有写错,不是双网双待,就是双网但不双待.所谓双网不双待,就是一个网卡只能访问外网,另一个网卡只能访问内网.) 1. 问题背景 我有一台电脑,电脑上有一个无线网卡,一个有线网卡.只有无线网卡才能访问互联网(外网),当然,也只有有限网卡才能访问私有网(内网). 2. 两个需求 需求之一:让