点连通度 边连通度 最大流最小割 最小割点集 最小割边集 & POJ 1966 Cable TV Network

概念

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

 

你可能感兴趣的:(点连通度 边连通度 最大流最小割 最小割点集 最小割边集 & POJ 1966 Cable TV Network)