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

「Luogu1345」[USACO5.4]奶牛的電信Telecowmunication

gis clu edge fine queue return 數量 需要 flow

「Luogu1345」[USACO5.4]奶牛的電信Telecowmunication

problem

Solution

題目要求找到最小數量的若幹個點,使得這些點被去掉之後,點\(c_1\)\(c_2\)不連通。

與最小割模型十分類似,考慮轉化


約定\((u,v,f)\)表示\(u\)\(v\)連邊,流量為\(f\)\(S\)為源,\(T\)為匯

先說模型

對於每個點\(u\),將其拆成\(u\times2,u\times2+1\)兩個點,建邊\((u\times2,u\times2+1,1)\)

對於原圖上的每條邊\((u,v)\),建邊\((u\times2+1,v\times2,inf)\)

最後令\(S=c_1\times2+1,T=c_2\times2\),求出最小割即可


為什麽這樣建模?

首先我們割的是而不是,我們需要在模型中將這個決策體現出來,因此需要將點拆成一個“入點”和一個“出點”。
去掉每個點對答案的貢獻為\(1\),所以入點和出點之間連一條流量為\(1\)的邊。割掉這條邊的意義即為去掉了這個點。

然後對於原圖上的無向邊,可以視作兩條方向相反的有向邊
對於每條有向邊\((u,v)\),相當於是從\(u\)“出來”,“進入”了\(v\),所以從\(u\)對應的出點向\(v\)對應的入點連邊,流量為正無窮

由於我們是從\(c_1\)出發到達\(c_2\),所以源是\(c_1\)

對應的出點,匯是\(c_2\)對應的入點

顯然最小割一定只包括流量為\(1\)的邊

Code

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define i(u) ((u)<<1)//入
#define o(u) (((u)<<1)|1)//出
using namespace std;
typedef long long ll;

template <typename T> void read(T &t)
{
    t=0;int f=0;char c=getchar();
    while(!isdigit(c)){f|=c=='-';c=getchar();}
    while(isdigit(c)){t=t*10+c-'0';c=getchar();}
    if(f)t=-t;
}

const int inf=0x3f3f3f3f;
const int maxn=1005,maxm=6005;
int n,m;
int S,T,c1,c2;
int ans;
 
struct edge
{
    int u,v,f,nxt;
}g[maxm*2];

int head[maxn],ecnt=1;
void eADD(int u,int v,int f)
{
//  cerr<<u<<" "<<v<<" "<<f<<endl;
    g[++ecnt].u=u;g[ecnt].v=v;g[ecnt].f=f;g[ecnt].nxt=head[u];head[u]=ecnt;
    g[++ecnt].u=v;g[ecnt].v=u;g[ecnt].f=0;g[ecnt].nxt=head[v];head[v]=ecnt;
}

int dep[maxn];
bool BFS()
{
    queue<int> q;
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    q.push(S);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();    
        for(register int i=head[u];i;i=g[i].nxt)
        {
            int v=g[i].v;
            if(!dep[v] && g[i].f)
            {
                dep[v]=dep[u]+1;
                if(v==T)return true;
                q.push(v);
            }
        }
    }
    return false;
}

int dfs(int u,int infl)
{
    if(u==T)return infl;
    int rest=infl;
    for(register int i=head[u];i && rest;i=g[i].nxt)
    {
        int v=g[i].v;
        if(dep[v]==dep[u]+1 && g[i].f)
        {
            int flow=dfs(v,min(g[i].f,rest));
            rest-=flow;
            g[i].f-=flow;
            g[i^1].f+=flow;
        }
    }
    return infl-rest;
}

int main()
{
    read(n),read(m),read(c1),read(c2);
    for(register int i=1;i<=n;++i)
        eADD(i(i),o(i),1);
    for(register int i=1;i<=m;++i)
    {
        int u,v;
        read(u),read(v);
        eADD(o(u),i(v),inf);
        eADD(o(v),i(u),inf);
    }
    S=o(c1),T=i(c2);
    while(BFS())
        ans+=dfs(S,inf);
    printf("%d",ans);
    return 0;
}

「Luogu1345」[USACO5.4]奶牛的電信Telecowmunication