P4126 [AHOI2009]最小割(网络流+tarjan)
作者:互联网
边$(x,y)$是可行流的条件:
1.满流;2.残量网络中$x,y$不连通
边$(x,y)$是必须流的条件:
1.满流;2.残量网络中$x,S$与$y,T$分别连通
现在的问题是怎么判断点之间是否连通
我们可以在残量网络上跑tarjan,处理出强连通分量
如果两点同属一个强连通分量,那么它们之间就连通辣
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; #define N 10005 #define M 1000005 int n,m,S,T,d[N],cur[N]; queue <int> h; bool vis[N]; int Clock,tp,st[N],dfn[N],low[N],be[N],bel; int cnt=1,hd[N],nxt[M],ed[N],poi[M],val[M],fr[M]; inline void adde(int x,int y,int v){ nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt, ed[x]=cnt, poi[cnt]=y, val[cnt]=v, fr[cnt]=x; } inline void link(int x,int y,int v){adde(x,y,v),adde(y,x,0);} bool bfs(){ memset(vis,0,sizeof(vis)); h.push(S); vis[S]=1; while(!h.empty()){ int x=h.front(); h.pop(); for(int i=hd[x];i;i=nxt[i]){ int to=poi[i]; if(!vis[to]&&val[i]>0) d[to]=d[x]+1,vis[to]=1,h.push(to); } }return vis[T]; } int dfs(int x,int a){ if(x==T||a==0) return a; int F=0,f; for(int &i=cur[x];i;i=nxt[i]){ int to=poi[i]; if(d[to]==d[x]+1&&(f=dfs(to,min(a,val[i])))>0) a-=f,F+=f,val[i]-=f,val[i^1]+=f; if(!a) break; }return F; } int dinic(){ int re=0; while(bfs()){ for(int i=1;i<=n;++i) cur[i]=hd[i]; re+=dfs(S,2e9); }return re; } void tarjan(int x){//板子 dfn[x]=low[x]=++Clock; st[++tp]=x; for(int i=hd[x];i;i=nxt[i]){ if(!val[i]) continue;//满流的不跑 int to=poi[i]; if(!dfn[to]) tarjan(to),low[x]=min(low[x],low[to]); else if(!be[to]) low[x]=min(low[x],dfn[to]); } if(dfn[x]==low[x]){ be[x]=++bel; while(st[tp]!=x) be[st[tp--]]=bel; --tp; } } int main(){ scanf("%d%d%d%d",&n,&m,&S,&T); for(int i=1,u,v,w;i<=m;++i) scanf("%d%d%d",&u,&v,&w),link(u,v,w); int tmp=dinic(); for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); for(int i=2;i<=cnt;i+=2){ printf((!val[i]&&be[fr[i]]!=be[poi[i]])?"1 ":"0 "); puts((!val[i]&&be[fr[i]]==be[S]&&be[poi[i]]==be[T])?"1":"0"); }return 0; }
标签:tarjan,连通,val,vis,AHOI2009,cnt,int,P4126,hd 来源: https://www.cnblogs.com/kafuuchino/p/10802132.html