POJ 1966 <点连通度>
题意:
给出点和边的个数n, m
给出相连点的边..形如(a, b)
求最少删去多少个点可以使存在不相邻的两个点不连通..
思路:
拆点+求最大流..
①. 构造一个容量网络N
②. 原图中的每个顶点变成网络N中的两个顶点v' 和 v'', 顶点v' 和 v''之间存在一条弧容量为1<确保这个点只可以路过一次..>
③. 原图G中的每条边e(u, v), 在N中都有对应弧为e'<u'', v'> 和 e''<u', v''>, e' 和 e'' 容量为INF<表示可以在任意两个点之间连线>
④. 遍历两两不相邻的点求最大流的最小值..
Tips:
※. 用EK算法可以在POJ上ac~但是学校OJ就会wa..因为POJ只要固定一个点就好~而学校的需要遍历两两不相邻的点..感觉是POJ的数据弱了..
※. 最大流用SAP算法能快点..
※. 源点为u'' 汇点为v'
Code:
POJ ac代码
1 #include <stdio.h> 2 #include <cstring> 3 #include <queue> 4 #define INF 0x1f1f1f1f 5 #define clr(x) memset(x, 0, sizeof(x)) 6 using namespace std; 7 8 int cap[155][155], flow[155][155]; 9 int p[155], a[155]; 10 int f, n, m; 11 12 void EK(int s, int t) 13 { 14 queue<int> q; 15 memset(flow, 0, sizeof(flow)); 16 memset(a, 0, sizeof(a)); 17 memset(p, 0, sizeof(p)); 18 f = 0; 19 while(1) 20 { 21 memset(a, 0, sizeof(a)); 22 a[s] = INF; 23 q.push(s); 24 while(!q.empty()) 25 { 26 int u = q.front(); 27 q.pop(); 28 for(int v = 1; v <= 2*n; ++v) 29 if(!a[v] && cap[u][v] > flow[u][v]) 30 { 31 p[v] = u; 32 q.push(v); 33 a[v] = a[u] < cap[u][v] - flow[u][v]? a[u]:cap[u][v] - flow[u][v]; 34 } 35 } 36 if(a[t] == 0) break; 37 for(int u = t; u != s; u = p[u]) 38 { 39 flow[p[u]][u] += a[t]; 40 flow[u][p[u]] -= a[t]; 41 } 42 f += a[t]; 43 } 44 } 45 46 int main() 47 { 48 int i, j, k; 49 int a, b; 50 while(scanf("%d %d", &n, &m) != EOF) 51 { 52 if(n == 0){ 53 puts("0"); 54 continue; 55 } 56 clr(cap); 57 58 for(i = 1; i <= n; ++i) 59 cap[i][i+n] = 1; 60 61 while(m--){ 62 scanf(" (%d,%d)", &a, &b); 63 cap[a+1+n][b+1] = cap[b+1+n][a+1] = INF; 64 } 65 int ans = INF; 66 67 for(i = 2; i <= n; ++i){ 68 EK(n+1, i); 69 if(f < ans) ans = f; 70 } 71 72 if(ans == INF) 73 printf("%d\n", n); 74 else 75 printf("%d\n", ans); 76 } 77 78 return 0; 79 }