割点和桥

57 篇文章 3 订阅
39 篇文章 0 订阅

点连通度与边连通度
在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合。一个图的点连通度的定义为,最小割点集合中的顶点数。
类似的,如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合。一个图的边连通度的定义为,最小割边集合中的边数。


双连通图、割点与桥
如果一个无向连通图的点连通度大于1,则称该图是点双连通的(point biconnected),简称双连通或重连通。一个图有割点,当且仅当这个图的点连通度为1,则割点集合的唯一元素被称为割点(cut point),又叫关节点(articulation point)。
如果一个无向连通图的边连通度大于1,则称该图是边双连通的(edge biconnected),简称双连通或重连通。一个图有桥,当且仅当这个图的边连通度为1,则割边集合的唯一元素被称为(bridge),又叫关节边(articulation edge)。
可以看出,点双连通与边双连通都可以简称为双连通,它们之间是有着某种联系的,下文中提到的双连通,均既可指点双连通,又可指边双连通。

求割点和桥

/*
* vis[v] 记录的是节点v当前的访问状态:1表示在栈中,0表示未访问,2表示已经访问
* dfn[v] 记录的是节点v被访问时的深度
* low[v] 记录的是点v可以到达的,访问时间最早的祖先
* 在深度遍历图的过程中,记录下每个节点的深度。
* 对当前节点cur,以及和它相连的点i,有两种情况
* (1)i没有被访问过,这时递归访问节点,并用i的可以到达的最早的祖先来更新cur的low值
* (2)i当前在栈中,这时说明图中有一个环,用i的深度更新cur的low值
*  
* cur是割点的条件:cur是根,且有大于一个儿子,或者cur不是根,且cur有一个儿子使得low[v]>dfn[cur]
* (cur,i)是桥的条件是Low[i]>dfn[cur]
* 
* 复杂度:O(|E|+|V|)
*  
* 输入:cur  当前节点
*      father  当前节点的父节点
*      dep  当前节点被访问时的深度
*      n  图的总点数
*      edge  图的邻接矩阵(从0开始编号)
*  
* 输出:bridge  全局变量,bridge[u][v]表示边(u,v)是否是一个桥
*      cut  全局变量  cut[v]表示节点v是否是一个割点
*/
const int MAXN = 1003;

int edge[MAXN][MAXN];
int bridge[MAXN][MAXN], cut[MAXN];
int low[MAXN], dfn[MAXN], vis[MAXN];
int ans;

void cut_bridge(int cur, int father, int dep, int n) {
    vis[cur] = 1;
    dfn[cur] = low[cur] = dep;
    int children = 0;
    for (int i = 0; i < n; i++) {
        if (edge[cur][i]) {
            if (i != father && 1 == vis[i]) {
                if (dfn[i] < low[cur]) {
                    low[cur] = dfn[i];
                }
            } else if (0 == vis[i]) {
                cut_bridge(i, cur, dep+1, n);
                children++;
                if (low[i] < low[cur]) {
                    low[cur] = low[i];
                }
                if ((father == -1 && children > 1) || (father != -1 && low[i] >= dfn[cur])) {
                    cut[cur] = true;
                }
                if (low[i] > dfn[cur]) {
                    bridge[cur][i] = bridge[i][cur] = true;
                }
            }
        }
    }
    vis[cur] = 2;
}

poj-1144-Network

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
const int inf=0x3ffffff;
const int MAXN = 103;
const double eps = 1e-6;

int edge[MAXN][MAXN];
int bridge[MAXN][MAXN], cut[MAXN];
int low[MAXN], dfn[MAXN], vis[MAXN];
int ans;

void cut_bridge(int cur, int father, int dep, int n) {
    vis[cur] = 1;
    dfn[cur] = low[cur] = dep;
    int children = 0;
    for (int i = 0; i < n; i++) {
        if (edge[cur][i]) {
            if (i != father && 1 == vis[i]) {
                if (dfn[i] < low[cur]) {
                    low[cur] = dfn[i];
                }
            } else if (0 == vis[i]) {
                cut_bridge(i, cur, dep+1, n);
                children++;
                if (low[i] < low[cur]) {
                    low[cur] = low[i];
                }
                if ((father == -1 && children > 1) || (father != -1 && low[i] >= dfn[cur])) {
                    ans += cut[cur] != true;
                    cut[cur] = true;
                }
                if (low[i] > dfn[cur]) {
                    bridge[cur][i] = bridge[i][cur] = true;
                }
            }
        }
    }
    vis[cur] = 2;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("1.txt", "r", stdin);
#endif
    int n, i, j, v, p, len;
    char str[1000];
    while(cin >> n, n) {
        memset(edge, 0, sizeof(edge));
        while(cin >> v, v) {
            v--;
            gets(str);
            len = strlen(str);
            int value = 0;
            for (i = 0; i < len; i++) {
                if (str[i] == ' ') {
                    if (value == 0) {
                        continue;
                    }
                    edge[v][value-1] = edge[value-1][v] = 1;
                    value = 0;
                } else {
                    value = value * 10 + str[i] - '0';
                }
            }
            if (value) {
                edge[v][value-1] = edge[value-1][v] = 1;
                value = 0;
            }
        }
        ans = 0;
        memset(vis, 0, sizeof(vis));
        memset(cut, 0, sizeof(cut));
        memset(bridge, 0, sizeof(bridge));
        for (i = 0; i < n; i++) {
            if (!vis[i]) {
                cut_bridge(i, -1, 0, n);
            }
        }
        cout << ans << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值