P1345 [USACO5.4]奶牛的电信Telecowmunication

原来这就是网络流啊!


以前总是听别人说:网络流难在建图。

现在终于明白了。这就是一道建图后求最小割的题目。

题目要求最少割掉几个点,才能使不连通。

所以这其实是一道最小割点的模板题。

如何求最小割点?网络流的最小割可是最小割边!

其实只需要做一点手脚就可以了。

对每一个点,可以抽象成两个点中间连一条边。

可以得知:如果想要走过这个点,那么就必须走他们之间的边。

那么就可以直接跑网络流得到答案了。

代码方面,使用\(i + n\)表示虚拟出来的结点。

注意起点是\(s + n\),终点是\(t\)。你总不会割掉起点和终点吧。。。

所以跑一遍有优化的dinic,直接0ms解决。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
const int maxn = 2005, INF = 0x3f3f3f3f;
struct Edges
{
    int next, to, weight;
} e[4000005];
int head[maxn], tot = 1;
int n, m, s, t;
int dep[maxn], cur[maxn];
void link(int u, int v, int w)
{
    e[++tot] = (Edges){head[u], v, w};
    head[u] = tot;
}
void add_Edges(int u, int v, int w)
{
    link(u, v, w);
    link(v, u, 0);
}
int read()
{
    int ans = 0; char ch = getchar();
    while(ch > '9' || ch < '0') ch = getchar();
    while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0', ch = getchar();
    return ans;
}
bool bfs()
{
    memset(dep, 0, sizeof(dep));
    std::queue<int> q;
    q.push(s + n); dep[s + n] = 1;
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i = head[u]; i; i = e[i].next)
        {
            int v = e[i].to;
            if(!dep[v] && e[i].weight)
            {
                dep[v] = dep[u] + 1;
                q.push(v);
            }
        }
    }
    return dep[t];
}
int dfs(int u, int flow)
{
    if(u == t) return flow;
    for(int &i = cur[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if(dep[v] == dep[u] + 1 && e[i].weight)
        {
            int di = dfs(v, std::min(flow, e[i].weight));
            if(di)
            {
                e[i].weight -= di;
                e[i ^ 1].weight += di;
                return di;
            }
        }
    }
    return 0;
}
int dinic()
{
    int ans = 0;
    while(bfs())
    {
        for(int i = 1; i <= n * 2; i++) cur[i] = head[i];
        while(int temp = dfs(s + n, INF)) ans += temp;
    }
    return ans;
}
int main()
{
    freopen("in.txt", "r", stdin);
    n = read(), m = read(), s = read(), t = read();
    for(int i = 1; i <= n; i++)
    {
        add_Edges(i, i + n, 1);
    }
    while(m--)
    {
        int x = read(), y = read();
        add_Edges(x + n, y, INF);
        add_Edges(y + n, x, INF);
    }
    printf("%d\n", dinic());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Garen-Wang/p/9247581.html