BZOJ_1797_[Ahoi2009]Mincut 最小割_最小割+tarjan
BZOJ_1797_[Ahoi2009]Mincut 最小割_最小割+tarjan
Description
A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci。现在B国想找出一个路径切断方案,使中转站s不能到达中转站t,并且切断路径的代价之和最小。 小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题: 问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 现在请你回答这两个问题。
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
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
首先求一遍最小割,然后在残量网络缩点。显然有S,T不在同一强连通分量中。
考虑边(u,v) ,如果u和v在同一scc中,那么割去这条边后仍有通路,因此它不会出现在任何一边的割集当中。
如果S和u在同一scc并且v和T在同一scc,那么假设在这条边上多加一些流量,那么从S到T则又可以增广,因此它一定会被割掉。
如果这条边没有满流,它同样不会被割掉。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 5000 #define M 120050 #define inf 100000000 #define mem(x) memset(x,0,sizeof(x)); int head[N],to[M],nxt[M],flow[M],n,m,cnt=1; int dep[N],Q[N],l,r,S,T; int St[N],top,ins[N],bl[N],scc,tot,dfn[N],low[N]; inline void add(int u,int v,int f){ to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;flow[cnt]=f; } bool bfs(){ l=r=0; mem(dep); Q[r++]=S;dep[S]=1; while(l<r){ int x=Q[l++]; for(int i=head[x];i;i=nxt[i]){ if(!dep[to[i]]&&flow[i]){ dep[to[i]]=dep[x]+1; if(to[i]==T)return 1; Q[r++]=to[i]; } } }return 0; } int dfs(int x,int mf){ if(x==T)return mf; int nf=0; for(int i=head[x];i;i=nxt[i]){ if(dep[to[i]]==dep[x]+1&&flow[i]){ int tmp=dfs(to[i],min(mf-nf,flow[i])); nf+=tmp; flow[i]-=tmp; flow[i^1]+=tmp; if(nf==mf)break; } } dep[x]=0;return nf; } void dinic(){ int ans=0,f=0; while(bfs()){ while(f=dfs(S,inf)){ ans+=f; } } } void tarjan(int x){ dfn[x]=low[x]=++tot; St[top++]=x;ins[x]=1; for(int i=head[x];i;i=nxt[i]){ if(flow[i]==0)continue; if(!dfn[to[i]]){ tarjan(to[i]); low[x]=min(low[x],low[to[i]]); }else if(!bl[to[i]]){ low[x]=min(low[x],dfn[to[i]]); } } if(low[x]==dfn[x]){ int t=St[--top];ins[t]=0; bl[t]=++scc; while(t^x){ t=St[--top];ins[t]=0; bl[t]=scc; } } } int main(){ scanf("%d%d%d%d",&n,&m,&S,&T); int x,y,z; for(int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); add(x,y,z);add(y,x,0); } dinic(); for(int i=1;i<=n;i++){ if(!dfn[i])tarjan(i); } for(int i=1;i<=m;i++){ if(flow[i<<1]){ printf("0 0\n");continue; } int g=to[i<<1|1],h=to[i<<1]; printf("%d %d\n",bl[g]!=bl[h],bl[g]==bl[S]&&bl[h]==bl[T]); /*if(bl[g]!=bl[h])printf("1"); else printf("0"); if(bl[g]==bl[S]&&bl[h]==bl[T])printf(" 1\n"); else printf(" 0\n");*/ } }