[BZOJ]1797: [Ahoi2009]Mincut 最小割 网络流+强连通

来源:互联网 发布:印度 网络空间 编辑:程序博客网 时间:2024/06/05 17:13

Description

A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci。现在B国想找出一个路径切断方案,使中转站s不能到达中转站t,并且切断路径的代价之和最小。 小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题: 问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 现在请你回答这两个问题。

Input

第一行有4个正整数,依次为N,M,s和t。第2行到第(M+1)行每行3个正 整数v,u,c表示v中转站到u中转站之间有单向道路相连,单向道路的起点是v, 终点是u,切断它的代价是c(1≤c≤100000)。 注意:两个中转站之间可能有多条道路直接相连。 同一行相邻两数之间可能有一个或多个空格。

Output

对每条单向边,按输入顺序,依次输出一行,包含两个非0即1的整数,分 别表示对问题一和问题二的回答(其中输出1表示是,输出0表示否)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

Sample Input

6 7 1 6

1 2 3

1 3 2

2 4 4

2 5 1

3 5 5

4 6 2

5 6 3

Sample Output

1 0

1 0

0 0

1 0

0 0

1 0

1 0

题解:

显然,只有满流边有可能被割。对于原图先跑一遍网络流,之后再对残量网络跑一遍强连通(此时的边包括反向弧)。对于每一条满流边,第一个问当belong[u]!=belong[v]时,输出1。(belong[i]为i所属的连通分量)因为u->v的这条边是满流的,它的反向边v->u显然不是满流,若u,v属于同一个连通分量,则u->v还存在路径,割掉此边无意义。第二个问,当belong[st]==belong[u]且belong[v]==belong[ed]时输出1。显然,缩点之后的图的最小割就是原图的最小割(割联通分量中的边无意义),所以满足以上条件,此边一定在割集中。

代码:

#include<cstdio>#include<cstring>#include<queue>#include<iostream>#include<algorithm>using namespace std;const int maxn=8000;int h[maxn];struct Edge{int x,y,d,next;}e[160010];int N,M,st,ed;int last[maxn],len=1;void ins(int x,int y,int d){    int t=++len;    e[t].x=x;e[t].y=y;e[t].d=d;    e[t].next=last[x];last[x]=t;}void addedge(int x,int y,int d){ins(x,y,d);ins(y,x,0);}queue<int>q;bool bfs(){    memset(h,0,sizeof(h));h[st]=1;    q.push(st);    while(!q.empty())    {        int x=q.front();q.pop();        for(int i=last[x];i;i=e[i].next)        if(h[e[i].y]==0&&e[i].d)q.push(e[i].y),h[e[i].y]=h[x]+1;    }    return h[ed];}int dfs1(int x,int f){    if(x==ed)return f;    int s=0,t;    for(int i=last[x];i;i=e[i].next)    {        int y=e[i].y;        if(h[y]==h[x]+1&&e[i].d&&s<f)        {            t=dfs1(y,min(f-s,e[i].d));            s+=t;e[i^1].d+=t;e[i].d-=t;        }    }    if(s==0)h[x]=0;    return s;}int low[maxn],dfn[maxn],id=0,sta[maxn],top=0,belong[maxn],cnt=0;bool in[maxn];void dfs2(int x){    sta[++top]=x;in[x]=true;    low[x]=dfn[x]=++id;    for(int i=last[x];i;i=e[i].next)    if(e[i].d)    {        int y=e[i].y;        if(dfn[y]==-1)dfs2(y),low[x]=min(low[x],low[y]);        else if(in[y])low[x]=min(low[x],dfn[y]);    }    if(low[x]==dfn[x])    {        cnt++;        int i;        do        {            i=sta[top--];            belong[i]=cnt;            in[i]=false;        }while(i!=x);    }}int main(){    memset(dfn,-1,sizeof(dfn));    scanf("%d%d%d%d",&N,&M,&st,&ed);    for(int i=1;i<=M;i++)    {        int v,u,c;        scanf("%d%d%d",&v,&u,&c);         addedge(v,u,c);    }    int ans=0;    while(bfs())ans+=dfs1(st,1<<30);    for(int i=1;i<=N;i++)    if(dfn[i]==-1)dfs2(i);    for(int i=2;i<=len;i+=2)    if(e[i].d)puts("0 0");    else    {        if(belong[e[i].x]!=belong[e[i].y])printf("1 ");        else printf("0 ");        if(belong[e[i].x]==belong[st]&&belong[e[i].y]==belong[ed])puts("1");        else puts("0");    }}
阅读全文
2 0