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

来源:互联网 发布:淘宝卖家屏蔽买家消息 编辑:程序博客网 时间:2024/04/30 13:10

最大流最小割

题目传送门

最大流打挂好几次。。。

根据最大流最小割定理,最小割的容量=最大流的值,所以直接跑最大流就可以啦!

先拆点,把每个点拆成出点和入点。对于一条路径i,j,建一条从i的出点指向j的入点容量为inf的边。因为路径双向,因此再建一条从j的出点指向i的入点容量为inf的边。
对于每个点,建一条从入点指向出点容量为1的边。

跑的时候要从s的出点跑到t。因为不能把s给割掉。

代码:

#include<cstdio>#include<cstring>#include<algorithm>#define MAXN 2000#define MAXM 600#define inf 0x7fffffffusing namespace std;struct edge{    int next,to,flow,v;}ed[MAXM*10+5];struct father{    int e,x;}fa[MAXN+5];int n,m,k,s,t;int h[MAXN+5],rem[MAXN+5],que[MAXN+5];bool f[MAXN+5];int bfs(){//EK    memset(f,false,sizeof(f));    int r=0,w=1; que[1]=s; f[s]=true; rem[s]=inf;    while (r<w){        int x=que[++r];        for (int i=h[x];~i;i=ed[i].next)            if (!f[ed[i].to]&&ed[i].v>ed[i].flow){                int v=ed[i].to;                que[++w]=v; f[v]=true; fa[v].e=i; fa[v].x=x;                rem[v]=min(rem[x],ed[i].v-ed[i].flow);                if (v==t) return rem[v];            }    }    return 0;}void change(int sum){    int now=t;    while (now!=s){        int e=fa[now].e;        ed[e].flow+=sum; ed[e^1].flow-=sum; now=fa[now].x;    }}int maxflow(){    int ans=0,sum;    while (sum=bfs())        ans+=sum,change(sum);    return ans;}void addedge(int x,int y,int z){    ed[k].next=h[x]; ed[k].to=y; ed[k].v=z; h[x]=k++;    ed[k].next=h[y]; ed[k].to=x; ed[k].v=0; h[y]=k++;}int main(){    scanf("%d%d%d%d",&n,&m,&s,&t);    memset(h,-1,sizeof(h));    for (int i=1;i<=m;i++){        int u,v; scanf("%d%d",&u,&v);        addedge(v+n,u,inf); addedge(u+n,v,inf);//拆点    }    for (int i=1;i<=n;i++) addedge(i,i+n,1);//拆点    s+=n;    printf("%d\n",maxflow());} 
阅读全文
1 0