bzoj1797: [Ahoi2009]Mincut 最小割

来源:互联网 发布:2016新疆4g网络关闭 编辑:程序博客网 时间:2024/06/05 15:15

传送门
显然先跑一遍网络流。
在残余网络上跑tarjan求出所有SCC,
记id[u]为点u所在SCC的编号。显然有id[s]!=id[t]
①对于任意一条满流边(u,v),(u,v)能够出现在某个最小割集中,当且仅当id[u]!=id[v];
②对于任意一条满流边(u,v),(u,v)必定出现在最小割集中,当且仅当id[u]==id[s]且id[v]==id[t]。

①<==将每个SCC缩成一个点,得到的新图就只含有满流边了。那么新图的任一s-t割都对应原图的某个最小割,从中任取一个把id[u]和id[v]割开的割即可证明。
②<==:假设将(u,v)的边权增大,那么残余网络中会出现s->u->v->t的通路,从而能继续增广,于是最大流流量(也就是最小割容量)会增大。这即说明(u,v)是最小割集中必须出现的边。

好吧,我承认我是看HZW的题解的。

#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<iostream>#include<algorithm>#define inf 0x3f3f3f3f#define N 4005using namespace std;struct edge{int from,to,f,next;}e[120005];int n,m,S,T,tot=1,tim,x,y,u,top,sum;int head[N],q[N],dis[N],v[N],dfn[N],id[N],low[N],st[N];void ins(int x,int y,int u){    e[++tot].from=x;    e[tot].to=y;    e[tot].f=u;    e[tot].next=head[x];    head[x]=tot;}bool bfs(){    int h=0,t=1,x;    memset(dis,-1,sizeof(dis));    dis[S]=0;    q[1]=S;    while (h<t){        x=q[++h];        for (int i=head[x];i;i=e[i].next)            if (e[i].f&&dis[e[i].to]==-1){                dis[e[i].to]=dis[x]+1;                q[++t]=e[i].to;            }    }    return dis[T]!=-1;}int dinic(int x,int f){    if (x==T) return f;    int r=f,k;    for (int i=head[x];i&&r;i=e[i].next)        if (e[i].f&&dis[e[i].to]==dis[x]+1){            k=dinic(e[i].to,min(r,e[i].f));            e[i].f-=k;            e[i^1].f+=k;            r-=k;        }    if (r) dis[x]=-1;    return f-r;}void tar(int x){    dfn[x]=low[x]=++tim;    st[++top]=x;    v[x]=1;    for (int i=head[x];i;i=e[i].next)        if (e[i].f){            if (!dfn[e[i].to]){                tar(e[i].to);                low[x]=min(low[x],low[e[i].to]);            }            else if (v[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);        }    int now=0;    if (dfn[x]==low[x]){        sum++;        while (now!=x){            now=st[top--];            id[now]=sum;            v[now]=0;        }    }}int main(){    scanf("%d%d%d%d",&n,&m,&S,&T);    for (int i=1;i<=m;i++){        scanf("%d%d%d",&x,&y,&u);        ins(x,y,u);        ins(y,x,0);    }    while (bfs()) dinic(S,inf);    for (int i=1;i<=n;i++) if (!dfn[i]) tar(i);    for (int i=2;i<=tot;i+=2)        if (e[i].f) printf("0 0\n");        else{            printf("%d ",(id[e[i].from]!=id[e[i].to])?1:0);            printf("%d\n",(id[e[i].from]==id[S]&&id[e[i].to]==id[T])?1:0);        }}
原创粉丝点击