POJ 1966 Cable TV Network 顶点连通度的求解
用拆点把点权变为边权。然后用最大流求解每对u、v(u != v),取其中的最小值
注意:
具体操作时,有个技巧,可以将枚举从O(n^2)优化到O(n):
先固定一个点,然后枚举另一个点即可。
很显然的一个结论:max_flow(1->2->3) < max_flow(2->3)
我们要取其中的最小,可以不必去求2->3的最大流
如果以1为源点,汇点只能是剩下的几个点,枚举汇点即可。
本题要多次求最大流,所以每求一次要重新还原原图
代码1:
先把原图的信息保存在map数组里,每次都重新建图。
View Code
#include<stdio.h> #include<string.h> #define maxn 110 #define maxm maxn*maxn #define inf 1000000000 int min(int a, int b) { return a < b ? a : b; } struct E { int v, next, c; }edge[maxm<<1]; int head[maxn], tot; int n, m; void init() { tot = 0; memset(head, -1, sizeof(head)); } void add(int s, int t, int c) { edge[tot].v = t; edge[tot].c = c; edge[tot].next = head[s]; head[s] = tot++; edge[tot].v = s; edge[tot].c = 0; edge[tot].next = head[t]; head[t] = tot++; } int pre[maxn]; int cur[maxn]; int dis[maxn]; int gap[maxn]; int sap(int s, int t, int n) { int i; for(i = 0; i <= n; i++) cur[i] = head[i], gap[i] = dis[i] = 0; gap[0] = n; int u = pre[s] = s, aug = inf, maxf = 0, v; while(dis[s] < n) { loop: for(i = cur[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].c && dis[u] == dis[v]+1) { aug = min(aug, edge[i].c); pre[v] = u; cur[u] = i; u = v; if(u == t) { while(u != s) { u = pre[u]; edge[cur[u]].c -= aug; edge[cur[u]^1].c += aug; } maxf += aug; aug = inf; } goto loop; } } int min_d = n; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].c && dis[v] < min_d) min_d = dis[v], cur[u] = i; } if( !(--gap[dis[u]]) ) break; ++gap[dis[u] = min_d + 1]; u = pre[u]; } return maxf; } int map[maxn][maxn]; void build() { int i, j; init(); for(i = 0; i < 2*n; i++) for(j = 0; j < 2*n; j++) if(map[i][j] && i != j) add(i, j, map[i][j]); } int main() { int i, j; int x, y; while( ~scanf("%d%d", &n, &m)) { init(); if(!m) { if(n == 1) printf("1\n"); else printf("0\n"); continue; } memset(map, 0, sizeof(map)); for(i = 0; i < n; i++) map[i][i+n] = 1; while(m--) { scanf(" (%d,%d)", &x, &y); map[x+n][y] = map[y+n][x] = inf; } int ans = n; for(i = 1; i < n; i++) { build(); ans = min( ans, sap(n, i, 2*n)); } printf("%d\n", ans); } return 0; }
代码2:
用反向边的信息还原原图,充分利用反向边的信息
View Code
#include<stdio.h> #include<string.h> #define maxn 104 #define maxm maxn*maxn #define inf 1000000000 int min(int a, int b) { return a < b ? a : b; } struct E { int v, next, c; }edge[maxm]; int head[maxn], tot; int n, m; int S, T; void init() { tot = 0; memset(head, -1, sizeof(head)); } void add(int s, int t, int c) { edge[tot].v = t; edge[tot].c = c; edge[tot].next = head[s]; head[s] = tot++; edge[tot].v = s; edge[tot].c = 0; edge[tot].next = head[t]; head[t] = tot++; } int pre[maxn]; int cur[maxn]; int dis[maxn]; int gap[maxn]; int sap(int s, int t, int n) { int i; for(i = 0; i <= n; i++) cur[i] = head[i], gap[i] = dis[i] = 0; gap[0] = n; int u = pre[s] = s, aug = inf, maxf = 0, v; while(dis[s] < n) { loop: for(i = cur[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].c && dis[u] == dis[v]+1) { aug = min(aug, edge[i].c); pre[v] = u; cur[u] = i; u = v; if(u == t) { while(u != s) { u = pre[u]; edge[cur[u]].c -= aug; edge[cur[u]^1].c += aug; } maxf += aug; aug = inf; } goto loop; } } int min_d = n; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].c && dis[v] < min_d) min_d = dis[v], cur[u] = i; } if( !(--gap[dis[u]]) ) break; ++gap[dis[u] = min_d + 1]; u = pre[u]; } return maxf; } void init_flow() { int i; for(i = 0; i < tot; i += 2) { edge[i].c += edge[i^1].c; edge[i^1].c = 0; } } int main() { int i, j; int x, y; while( ~scanf("%d%d", &n, &m)) { init(); if(!m) { if(n == 1) printf("1\n"); else printf("0\n"); continue; } for(i = 0; i < n; i++) add(i, i+n, 1); while(m--) { scanf(" (%d,%d)", &x, &y); add(x+n, y, inf); add(y+n, x, inf); } int ans = inf; for(i = 1; i < n; i++) { ans = min(ans, sap(n, i, 2*n)); init_flow(); } if(ans >= inf) ans = n; printf("%d\n", ans); } return 0; }


浙公网安备 33010602011771号