1. 程式人生 > >[USACO5.4]奶牛的電信

[USACO5.4]奶牛的電信

傳送門:[USACO5.4]奶牛的電信


題目描述

農夫約翰的奶牛們喜歡通過電郵保持聯絡,於是她們建立了一個奶牛電腦網路,以便互相交流。這些機器用如下的方式傳送電郵:如果存在一個由c臺電腦組成的序列 a 1 , a 2

, . . . , a c a_1,a_2,...,a_c ,且 a 1 a_1 a 2 a_2
相連, a 2 a_2 a 3 a_3 相連,等等,那麼電腦 a 1 a_1 a c a_c 就可以互發電郵。

很不幸,有時候奶牛會不小心踩到電腦上,農夫約翰的車也可能碾過電腦,這臺倒黴的電腦就會壞掉。這意味著這臺電腦不能再發送電郵了,於是與這臺電腦相關的連線也就不可用了。

有兩頭奶牛就想:如果我們兩個不能互發電郵,至少需要壞掉多少臺電腦呢?請編寫一個程式為她們計算這個最小值。

以如下網路為例:

1 / 3 2 1* / 3 - 2*

這張圖畫的是有 2 2 條連線的 3 3 臺電腦。我們想要在電腦 1 1 2 2 之間傳送資訊。電腦 1 1 3 3 2 2 3 3 直接連通。如果電腦 3 3 壞了,電腦 1 1 2 2 便不能互發資訊了。


分析

簡化題意,本題求的是無向圖的最小割點。
直接求是不可能的,可以考慮將割點轉化成割邊,然後直接求最大流。
對於如下的點

直接拆成這樣
在這裡插入圖片描述
然後跑最大流就行了
對於 S , T S, T ,從 S 2 S2 跑到 T 1 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;
}