pku 1966 Cable TV Network 点连通度
http://poj.org/problem?id=1966
这里是点连通度的一些介绍:
点连通度的定义:一个具有N个点的图G中,在去掉任意k-1个顶点后(1<=k<=N),所得的子图仍然连通,去掉K个顶点后不连通,则称G是K连通图,K称作图G的连通度,记作K(G)。
独立轨:A,B是图G(有向无向均可)的两个顶点,我们称为从A到B的两两无公共内顶的轨为独立轨,其最大的条数记作p(A,B)。
在上图中有一个具有7个定点的连通图,从顶点1到顶点3有3条独立轨,即p(1,3)=3;
1—2—3 , 1—7—3 , 1—6—5—4—3
如果分别从这3条独立轨中,每条轨抽出一个内点,在G图中删掉,则图不连通。若连通图G的两两不相邻顶点间的最大独立轨数最小的P(A,B)值即为K(G)。若G为完全图(两两点可达),则
K(G)=n-1,即完全把某个点的所有边删掉后才不连通。既然独立轨是只能经过一次的边,那么可以构造网络流模型,其中每条边的容量为1,就可以限制只经过一次。
构建网络流模型:
若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为有向图
(1)原G图中的每个顶点V变成N网中的两个顶点V`和V``,顶点V`至V``有一条容量为1的弧;
(2)原G图中的每条弧e=UV变成一条有向轨U`U``V`V``,其中轨上的弧U``V`的容量为无穷;
(3)以A``为源点,B`为汇点求最大流。
上面的模型只是求出了以A为源点B为汇点的最大流max_flow,等价于在G中只要去掉max_flow个点就会使得A与B不连通。而图的连通度是要求去掉最少的点使得整个图不连通,做法是固定一个点为源点,枚举与源点不相邻的点为汇点,求最大流。在所有的枚举结果中最小的max_flow值就是要求的K(G).注意如果某次枚举的汇点求出 的最大流为无穷则说明此此枚举的源点与汇点是强连通的。如果所有的枚举结果都为无穷,则说明整个图G是强连通的,需要去掉n-1个点才能破坏其连通性。
所有具有流量为1的弧(V`,V``)对应的V顶点组成一个割顶集
通过求连通度可以得到一个结论:G是K的连通图,k>=2,则任意K个顶点共圈。
求边连通度总结:
同样引入独立轨的概念,只是在这里叫弱独立轨,同样在每条弱独立轨中只有去掉某一条边就可以使起点到终点不连通,现在整个图G的边连通度就是要找出任意两点的弱独立轨的最小值。如果图G为完全图,则K`(G)为n-1。
构建一个网络N
若G为无向图:
1. 原G图中的每条边e=UV变成两条边e`=UV,e``=VU,容量都为1;
2. 固定一个点为源点,枚举与源点不相邻的为汇点,求最大流max_flow,保留最小的max_flow即为图的边连通度。
若G为有向图:
1. 原G图中每条有向边容量为1;
2. 此步骤与无向图的步骤2相同。
求出的残余网络中,流量为1的弧e`=(u,v),则e`就是桥。
从图的边连通度中可以得到以下结论:
1. A是有向图G的一个顶点,如果A与G的其他所有点V间的最小值为K,则G中存在以A为根的K棵无公共边的生成树;
2. 设G是有向图,0<k<=K`(G),L是0至k之间任意一个整数,对于图G的任意一对顶点(u,v)来说,存在U到V的L条弱独立有向轨,同时存在从V到U的L-k条弱独立有向轨。
题意:
给出一张图,求去点最少的点使得该图变为不连通的图;
思路:
按照求点连通度的思路求解。
//#pragma comment(linker,"/STACK:327680000,327680000") #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define inf 0x7f7f7f7f #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll long long #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x)int #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define N 1005 using namespace std; struct node { int v,w; int next; }g[N*N*2];//开始这里边开小了wa多次,郁闷啊 int head[N],ct; int hash[N][N]; int tab[N][2]; int level[N],q[1000004]; int n,m; void add(int u,int v,int w) { g[ct].v = v; g[ct].w = w; g[ct].next = head[u]; head[u] = ct++; g[ct].v = u; g[ct].w = 0; g[ct].next = head[v]; head[v] = ct++; } //关键是建图 void build(int x,int y) { int i; CL(head,-1); ct = 0; //拆点边权为1 for (i = 1; i <= n; ++i) add(i,i + n,1); //原图中的边,边权为inf for (i = 0; i < m; ++i) { add(tab[i][0] + n,tab[i][1],inf); add(tab[i][1] + n,tab[i][0],inf); } //这里不是很理解...... add(x,x + n,inf); add(y,y + n,inf); } bool layer(int s,int e) { int i; CL(level,-1); queue<int>q; q.push(s); level[s] = 1; while (!q.empty()) { int u = q.front(); q.pop(); for (i = head[u]; i != -1; i = g[i].next) { int v = g[i].v; int w = g[i].w; if (w > 0 && level[v] == -1) { level[v] = level[u] + 1; if (v == e) return true; q.push(v); } } } return false; } int find(int s,int e) { int i; int top = 1,u; int ans = 0; while (top) { if (top == 1) u = s; else u = g[q[top - 1]].v; if (u == e) { int MIN = inf,pos = 0; for (i = 1; i <= top - 1; ++i) { if (MIN > g[q[i]].w) { MIN = g[q[i]].w; pos = i; } } for (i = 1; i <= top - 1; ++i) { g[q[i]].w -= MIN; g[q[i]^1].w += MIN; } ans += MIN; top = pos; } else { for (i = head[u]; i != -1; i = g[i].next) { int w = g[i].w; int v = g[i].v; if (level[v] == level[u] + 1 && w > 0) { q[top++] = i; break; } } if (i == -1) { top--; level[u] = -1; } } } return ans; } int dinic(int s,int e) { int ans = 0; while (layer(s,e)) ans += find(s,e); return ans; } int main() { Read(); int i,j; int x,y; while (~scanf("%d%d",&n,&m)) { if (m == 0) { if (n == 1) printf("1\n"); else printf("0\n"); continue; } CL(hash,0); for (i = 0; i < m; ++i) { scanf(" (%d,%d)",&x,&y); x++; y++; tab[i][0] = x; tab[i][1] = y; hash[x][y] = 1; } int ans = inf; int sign = 0;//如果全部联通的话该图为强连通图,那么它的点连通度为n for (i = 1; i <= n; ++i) { for (j = i + 1; j <= n; ++j) { if (!hash[i][j]) { sign = 1; build(i,j); int res = dinic(i,j + n); ans = min(ans,res); } } } if (!sign) printf("%d\n",n); else printf("%d\n",ans); } return 0; }