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

求最小的割点数

将点拆成两个点,加入额外的边来约束,(x o x') 流量为 1 的边

  • 最大流等于最小割

证明

考虑跑完最大流的图,无法找到从 (S)(T) 通路,也就是说图被满流的边分成了两部分,连接两个部分的边就是最小割,且他们的权值加起来就是最大流

从最小割的角度来看,一但割去的边 (<) 最大流,那一定可以找到 (S)(T) 的通路

#include<bits/stdc++.h>
using namespace std;
#define rg register
inline int read(){
    rg char ch=getchar();
    rg int x=0,f=0;
    while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return f?-x:x;
} 
int n,m,s,t;
int head[100010],ver[100010],nxt[100010],flow[100010],hh[100010],tot=1;
int dis[100010],ans;
const int inf=99999999;
inline void add(int x,int y,int z){
    ver[++tot]=y;
    flow[tot]=z;
    nxt[tot]=head[x];
    head[x]=tot;
}

int bfs(){
    for(int i=0;i<=(n<<1);++i) hh[i]=head[i];
    queue<int> q;
    q.push(s);
    memset(dis,-1,sizeof dis);
    dis[s]=0;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int y,i=head[x];i;i=nxt[i]){
            y=ver[i];
            if(dis[y]==-1&&flow[i]){
                dis[y]=dis[x]+1;
                q.push(y);
            }
        }
    }
    return dis[t]==-1?false:true;
}

int dfs(int x,int f){
    if(x==t||!f)return f;
    int used=0;
    for(int w,y,&i=hh[x];i;i=nxt[i]){
        y=ver[i];
        if(dis[y]==dis[x]+1&&flow[i]){
            w=dfs(y,min(f-used,flow[i]));
            if(w){
                flow[i]-=w;
                flow[i^1]+=w;
				used+=w;
                if(used==f) return f;
            }
        }
    }
    return used;
}

inline void dinic(){
    while(bfs()) ans+=dfs(s,99999999);
}

int main(){
    n=read(),m=read(),s=read()+n,t=read();
    for(int i=1;i<=n;++i) add(i,i+n,1),add(i+n,i,0);
    for(int x,y,i=1;i<=m;++i){
        x=read(),y=read();
        add(x+n,y,inf);
        add(y,x+n,0);
        add(y+n,x,inf);
    	add(x,y+n,0);
	}
    dinic();
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/XiaoVsun/p/13098588.html