概念
(1)一个具有 N 个顶点的图,在去掉任意 k-1 个顶点后 (1<=K<=N) 所得的子图仍连通
,而去掉 K 个顶点后的图不连通则称 G 是连通的, K 称作图 G 的点连通度,记作 K(G) 试设计
(2)相应地如果至少去掉 K 条边使这个图不连通,则 K 成为图的边连通度
等价关系
(1)求边连通度给每条边赋权值 1 ,任意选择源点,枚举汇点,依次求最小割,取其中的最小值即可
(2)那么给定源点和汇点时怎么求最小割呢,那就用到了最大流最小割定理,即一个图的小割等于其源点与汇店间的最大流
(3) 如何求一个图的最小割边集呢:最大流最小割定理,首先求得最大流。然后残留网络中,从源点出发深度优先遍历,所有被遍历到的点构成点集 SET1 ,剩余的点构成点集 SET2 。则 edge<SET1,SET2> 即是最小割的割边集
(4)求一个给定的无向图的点连通度,可以转换为求边连通度,怎么转换就如下所示:
将点连通度转化为边连通度时怎么建图呢:
1 .构造一个网络 N
若 G 为无向图:
(1) 原 G 图中的每个顶点 v 变成 N 网中的两个顶点 v' 和 v" ,顶点 v' 至 v" 有一条弧(有向边)连接,弧容量为 1;
(2) 原 G 图中的每条边 e = uv ,在 N 网中有两条弧 e’= u"v',e"=v"u' 与之对应, e' 弧容量为 ∞ , e" 弧容量为 ∞
(3)A” 为源顶点, B' 为汇顶点
注意:弧是有向边
若 G 为有向图:
(I) 原 G 图中的每个顶点变成 N 网中的两个顶点 v’ 和 v” ,顶点 v' 至 v” 有一条弧连接,弧容量为 1
(2) 原 G 图中的每条弧 e = uv 变成一条有向轨 u'u"v'v" ,其中轨上的弧 u"v' 的容量为 ∞;
(3)A” 为源顶点, B' 为汇顶点
2 .指定一个源点 A" ,枚举汇点,求 A" 到 B' 的最大流 F
3 .求出所有枚举源点与汇点中的最小值 Fmin ,则所有具有流量 1 的弧 (v',v") 对应的 v 顶点组成一个割顶集,在 G 图中去掉这些顶点则 G 图变成不连通。
4 。求出的结果如果 Fmin >= n 则表示这个图是一个强连通图,不存在割点
下面举个求点连通度的例子 POJ 1966 Cable TV Network
#include <iostream>
#define MAX_N 105
#define MAX_VAL 99999999
#include <queue>
using namespace std;
char temp[20];
int n, m, minCutNum;
//保存边1-2*n不保存实际的边,而作为邻接表的入口
struct edge
{
int to;
int next;
}edges[MAX_N * MAX_N + MAX_N];
int edgen;
int graph[MAX_N][MAX_N];
int df[MAX_N][MAX_N], f[MAX_N][MAX_N];
int pre[MAX_N];
bool v[MAX_N];
queue<int> bfsq;
//插入边
void insertEdge(int from, int to)
{
edgen++;
edges[edgen].to = to;
edges[edgen].next = edges[from].next;
edges[from].next = edgen;
}
//bfs找增广路径
int bfs(const int &source, const int &dest)
{
memset(v, 0, sizeof(v));
memset(pre, 0, sizeof(pre));
while(!bfsq.empty()) bfsq.pop();
v[source] = true;
bfsq.push(source);
while(!bfsq.empty())
{
int curid = bfsq.front();
bfsq.pop();
if(curid == dest) break;
int next = edges[curid].next, nextid;
while(next != 0)
{
nextid = edges[next].to;
if(!v[nextid] && df[curid][nextid] > 0)
{
v[nextid] = true;
pre[nextid] = curid;
bfsq.push(nextid);
}
next = edges[next].next;
}
}
if(!pre[dest]) return -1;
int preid, curid = dest, curminw = MAX_VAL;
while((preid = pre[curid]) != 0)
{
if(df[preid][curid] < curminw) curminw = df[preid][curid];
curid = preid;
}
return curminw;
}
//最大流算法
int admonsKarp(const int &source, const int &dest)
{
int val;
memcpy(df, graph, sizeof(graph));
memset(f, 0, sizeof(f));
while((val = bfs(source, dest)) != -1)
{
//更新残留网络与权值网络
int preid, curid = dest;
while((preid = pre[curid]) != 0)
{
df[preid][curid] -= val;
df[curid][preid] += val;
f[preid][curid] += val;
f[curid][preid] = -f[preid][curid];
curid = preid;
}
}
int next = edges[source].next, toid, total = 0;
while(next != 0)
{
toid = edges[next].to;
total += f[source][toid];
next = edges[next].next;
}
return total;
}
int main()
{
int i, p;
while(scanf("%d%d", &n, &m) != EOF)
{
edgen = 2 * n;
minCutNum = MAX_VAL;
memset(edges, 0, sizeof(edges));
memset(graph, 0, sizeof(graph));
//建图,将点连通度转换为边连通度
for(i = 1; i <= m; i++)
{
scanf("%s", temp);
int val1 = 0, val2 = 0;
p = 1;
while(temp[p] != ',')
{
val1 = val1 * 10 + int(temp[p] - '0');
p++;
}
p++;
while(temp[p] != ')')
{
val2 = val2 * 10 + int(temp[p] - '0');
p++;
}
val1++; val2++;
graph[val1 + n][val2] = MAX_VAL;
graph[val2 + n][val1] = MAX_VAL;
insertEdge(val1 + n, val2);
insertEdge(val2 + n, val1);
}
for(i = 1; i <= n; i++)
{
graph[i][i + n] = 1;// = graph[i + n][i] = 1;
insertEdge(i, i + n);
//insertEdge(i + n, i);
}
int curcutnum;
for(i = 2; i <= n; i++)
{
curcutnum = admonsKarp(1 + n, i);
if(curcutnum < minCutNum) minCutNum = curcutnum;
}
if(minCutNum >= n) printf("%d/n", n);
else printf("%d/n", minCutNum);
}
return 0;
}