概念
(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;
}