[USACO5.4]奶牛的电信Telecowmunication

题面描述

农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,…,a(c),且a1与a2相连,a2与a3相连,等等,那么电脑a1和a(c)就可以互发电邮。

很不幸,有时候奶牛会不小心踩到电脑上,农夫约翰的车也可能碾过电脑,这台倒霉的电脑就会坏掉。这意味着这台电脑不能再发送电邮了,于是与这台电脑相关的连接也就不可用了。

有两头奶牛就想:如果我们两个不能互发电邮,至少需要坏掉多少台电脑呢?请编写一个程序为她们计算这个最小值。

以如下网络为例:

​ 1

/

3 —- 2

这张图画的是有2条连接的3台电脑。我们想要在电脑1和2之间传送信息。电脑1与3、2与3直接连通。如果电脑3坏了,电脑1与2便不能互发信息了。

输入格式

第一行 四个由空格分隔的整数:N,M,c1,c2.N是电脑总数,电脑由1到N编号。M是电脑之间连接的总数。最后的两个整数c1和c2是上述两头奶牛使用的电脑编号。连接没有重复且均为双向的(即如果c1与c2相连,那么c2与c1也相连)。两台电脑之间至多有一条连接。电脑c1和c2不会直接相连。

第2到M+1行 接下来的M行中,每行包含两台直接相连的电脑的编号。

输出格式

一个整数表示使电脑c1和c2不能互相通信需要坏掉的电脑数目的最小值。

样例

输入

1
2
3
3 2 1 2
1 3
2 3

输出

1
1

数据范围

1<=N<=100, 1<=M<=600

思路

求最小割点集的大小

将每个点拆成点$u$和点$u + n$,从$u$到$u+ n$ 连一条边权为$1$的边。

1
2
addedge(u, u + n, 1);
addedge(u + n, u, 0);

对于图中原来存在的边$u \implies v$ ,使$u + n$连向$v$, $v + n$ 连向$u$ ,边权都为无穷大。

1
2
3
4
addedge(u + n, v, INF);
addedge(v, u + n, 0);
addedge(v + n, u, INF);
addedge(u, v + n, 0);

然后对然后以源点$S + n$,汇点$T$跑一边最大流就行了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# include <bits/stdc++.h>
# define MAXN 123
# define INF 0x7fffffff
using namespace std;
inline char getc() {
static char buf[1 << 18], *fs, *ft;
return (fs == ft && (ft = (fs = buf) + fread(buf, 1, 1 << 18, stdin)), fs == ft) ? EOF : *fs++;
}
inline int gn() {
register int k = 0, f = 1;
register char c = getc();
for(; !isdigit(c); c = getc()) if(c == '-') f = -1;
for(; isdigit(c); c = getc()) k = k * 10 + c - '0';
return f * k;
}
struct edge {
int to, w, ne;
edge() {;}
edge(int to_, int w_, int ne_) {
to = to_, ne = ne_, w = w_;
}
}e[MAXN << 5];
int cnt, head[MAXN << 1], s, t, n, m;
inline void addedge(int fr, int to, int w) {
e[cnt] = edge(to, w, head[fr]), head[fr] = cnt++;
e[cnt] = edge(fr, 0, head[to]), head[to] = cnt++;
}
int dis[MAXN << 1];
queue <int> q;
inline bool bfs() {
memset(dis, -1, sizeof(dis));
q.push(s);
dis[s] = 0;
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = head[u]; ~i; i = e[i].ne) {
int v = e[i].to;
if(!~dis[v] && e[i].w > 0) {
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
return ~dis[t];
}
int dfs(int u, int val) {
int rec = 0;
if(u == t) return val;
for(int i = head[u]; ~i; i = e[i].ne) {
int v = e[i].to;
if(dis[v] == dis[u] + 1 && e[i].w > 0 && (rec = dfs(e[i].to, min(val, e[i].w)))) {
e[i].w -= rec;
e[i ^ 1].w += rec;
return rec;
}
}
return 0;
}
inline int max_flow() {
int ans = 0, u;
while(bfs()) {
while(u = dfs(s, INF)) ans += u;
}
return ans;
}
int main() {
memset(head, -1, sizeof(head));
n = gn(), m = gn(), s = gn() + n, t = gn();
for(int i = 1; i <= n; i++) addedge(i, i + n, 1);
for(int x, y, i = 1; i <= m; i++) {
x = gn(), y = gn();
addedge(x + n, y, INF);
addedge(y + n, x, INF);
}
printf("%d\n", max_flow());
}