无向图的顶点连通度
无向图的顶点连通度需要用到网络流来求,并且有以下定理;
Mengerg定理: 无向图的顶点连通度K和顶点间的最大独立轨数目之间存在如下关系:
① 当图为完全图时: k=V-1 (V表示图中顶点数)
② 当图为非完全图h时: K=min{ P(A, B) | 任意不相邻的顶点AB }
注意:如果AB相邻的话,那么删除图中所有其他的点后,AB任然连通,故强调不相邻。
独立轨:设A,B是无向图G的两个顶点,从A到B的两条没有公共顶点的路径,互称为独立轨。
最大独立轨数:A到B独立轨的最大条数,记作P(A,B)。
现在,求无向图G的顶点连通度就相当于求G中任意两点间u最大独立轨数(P(A,B))的最小值。
求P(A,B)的方法如下:
(1) 构造一个容量网络。
① 原图G中每个顶点v拆分为两个点v1 v2 ,并且v1 v2 之间连一条容量为1的单向弧。
② 原图G中每条变e=(u,v)在容量网络中有两条弧e1 =(u1 , v2 ),e2 =(u2 , v1 ),容量均为INF。
③ 另设A2 为源点,B1 为汇点。
(2)求从A2 到B1 的最大流F。
(3)流处源点的流量之和就是P(A,B),所有具有流量1的弧<v,v>对应的顶点v构成一个割顶集,删除这个割顶集,A,B之间不在连通。
所以,根据以上定理,得出求无向图G的顶点连通度的思路:
(1) 设K的初始值为INF。
(2) 分析图中每对不相邻的顶点AB,求出P(A,B)和割顶集。
(3) K=min (K, P(A,B)),保存割顶集。
(4) 重复(2)(3),直到图中所有不相邻顶点分析完为止。
给出POJ1966代码:
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #define _Clr(x, y) memset(x, y, sizeof(x)) #define INF 0x3f3f3f3f #define N 300 using namespace std; int map[N][N], flow[N][N]; int que[N], n, St[N]; int alpha[N], pre[N]; // 求S到T的最大流 int MaxFlow(int S, int T) { int maxf=0, m=2*n; _Clr(flow, 0); queue<int> Q; while(1) { _Clr(pre, -1); _Clr(alpha, 0); pre[S] = S; alpha[S] = INF; Q.push(S); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i=0; i<m; i++) { if(pre[i]==-1 && flow[u][i]<map[u][i]) { pre[i] = u; alpha[i] = min(alpha[u], (map[u][i]-flow[u][i])); Q.push(i); } } } if(alpha[T] == 0) break; maxf += alpha[T]; for(int i=T; i!=S; i=pre[i]) { flow[pre[i]][i] += alpha[T]; flow[i][pre[i]] -= alpha[T]; } } return maxf; } void BuildMap(int m) { int a, b; _Clr(map, 0); for(int i=0; i<n; ++i) map[i][i+n] = 1; while(m--) { scanf(" (%d,%d)", &a, &b); map[a+n][b] = map[b+n][a] = INF; } } int main() { int m; while(~scanf("%d%d", &n, &m)) { BuildMap(m); int ans=INF; for(int i=1; i<n; i++) ans = min(ans, MaxFlow(n, i)); printf("%d\n", ans==INF?n:ans); } return 0; }