版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27121257/article/details/82963070
传送门:[USACO5.4]奶牛的电信
题目描述
农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列 ,且 与 相连, 与 相连,等等,那么电脑 和 就可以互发电邮。
很不幸,有时候奶牛会不小心踩到电脑上,农夫约翰的车也可能碾过电脑,这台倒霉的电脑就会坏掉。这意味着这台电脑不能再发送电邮了,于是与这台电脑相关的连接也就不可用了。
有两头奶牛就想:如果我们两个不能互发电邮,至少需要坏掉多少台电脑呢?请编写一个程序为她们计算这个最小值。
以如下网络为例:
这张图画的是有 条连接的 台电脑。我们想要在电脑 和 之间传送信息。电脑 与 、 与 直接连通。如果电脑 坏了,电脑 与 便不能互发信息了。
分析
简化题意,本题求的是无向图的最小割点。
直接求是不可能的,可以考虑将割点转化成割边,然后直接求最大流。
对于如下的点
直接拆成这样
然后跑最大流就行了
对于
,从
跑到
代码
#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;
}