传送门:[USACO5.4]奶牛的电信
题目描述
农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列 a 1 , a 2 , . . . , a c a_1,a_2,...,a_c a1,a2,...,ac,且 a 1 a_1 a1与 a 2 a_2 a2相连, a 2 a_2 a2与 a 3 a_3 a3相连,等等,那么电脑 a 1 a_1 a1和 a c a_c ac就可以互发电邮。
很不幸,有时候奶牛会不小心踩到电脑上,农夫约翰的车也可能碾过电脑,这台倒霉的电脑就会坏掉。这意味着这台电脑不能再发送电邮了,于是与这台电脑相关的连接也就不可用了。
有两头奶牛就想:如果我们两个不能互发电邮,至少需要坏掉多少台电脑呢?请编写一个程序为她们计算这个最小值。
以如下网络为例:
1 ∗ / 3 − 2 ∗ 1* / 3 - 2* 1∗/3−2∗
这张图画的是有 2 2 2条连接的 3 3 3台电脑。我们想要在电脑 1 1 1和 2 2 2之间传送信息。电脑 1 1 1与 3 3 3、 2 2 2与 3 3 3直接连通。如果电脑 3 3 3坏了,电脑 1 1 1与 2 2 2便不能互发信息了。
分析
简化题意,本题求的是无向图的最小割点。
直接求是不可能的,可以考虑将割点转化成割边,然后直接求最大流。
对于如下的点
直接拆成这样
然后跑最大流就行了
对于
S
,
T
S, T
S,T,从
S
2
S2
S2跑到
T
1
T1
T1
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#define IL inline
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
const int inf(0x3f3f3f3f);
int to[3505], nxt[3505], val[3505];
int cnt, last[505];
IL void add(int u, int v, int w)
{
to[++cnt] = v; nxt[cnt] = last[u]; val[cnt] = w; last[u] = cnt;
to[++cnt] = u; nxt[cnt] = last[v]; val[cnt] = 0; last[v] = cnt;
}
int S, T;
int dis[505], cur[505];
queue<int>Q;
IL int min_(int x, int y) { return x < y ? x : y; }
IL bool bfs()
{
memset(dis, 0, sizeof(dis));
for(; !Q.empty(); Q.pop());
Q.push(S); dis[S] = 1;
for(int u, v; !Q.empty();)
{
u = Q.front(); Q.pop();
for(int i = last[u]; i != -1; i = nxt[i])
if(val[i] && !dis[(v = to[i])])
{
dis[v] = dis[u] + 1;
if(v == T) return 1;
Q.push(v);
}
}
return 0;
}
IL int dfs(int u, int maxf)
{
if(!maxf || u == T) return maxf;
int flow = 0;
for(int &i = cur[u], v, f; i != -1; i = nxt[i])
if(val[i] && dis[(v = to[i])] == dis[u] + 1 && (f = dfs(v, min_(val[i], maxf))))
{
val[i] -= f;
val[i ^ 1] += f;
flow += f;
if(!(maxf -= f)) return flow;
}
return flow;
}
IL int max_flow()
{
int flow = 0;
//memcpy(cur, last, sizeof(last));
for(; bfs();)
{
memcpy(cur, last, sizeof(last));
flow += dfs(S, inf);
}
return flow;
}
int main()
{
int n = read(), m = read();
S = read() + n; T = read();
memset(last, -1, sizeof(last));
cnt = -1;
for(int i = 1; i <= n; ++i)
{
add(i, i + n, 1);
}
for(int i = 1, x, y; i <= m; ++i)
{
x = read(); y = read();
add(y + n, x, inf);
add(x + n, y, inf);
}
printf("%d\n", max_flow());
return 0;
}