还是引用鏼爷的题解吧。。。
我不会做qwq。
jcvb:
在残余网络上跑tarjan求出所有SCC,记id[u]为点u所在SCC的编号。显然有id[s]!=id[t](否则s到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)是最小割集中必须出现的边。
#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 1000000007
using namespace std;
int n,m,S,T,cnt=1,tot,scc,top;
int head[5005],cur[5005],dis[5005],q[5005],belong[5005],dfn[5005],low[5005],stack[5005];
int next[150005],list[150005],key[150005],from[150005];
bool inset[5005];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void insert(int x,int y,int z)
{
next[++cnt]=head[x];
head[x]=cnt;
from[cnt]=x;
list[cnt]=y;
key[cnt]=z;
}
inline bool BFS()
{
memset(dis,-1,sizeof(dis));
dis[S]=1; q[1]=S;
int t=0,w=1,x;
while (t<w)
{
x=q[++t];
for (int i=head[x];i;i=next[i])
if (key[i]&&dis[list[i]]==-1)
dis[list[i]]=dis[x]+1,q[++w]=list[i];
}
return dis[T]!=-1;
}
int find(int x,int flow)
{
if (x==T) return flow;
int w,used=0;
for (int i=cur[x];i;i=next[i])
if (key[i]&&dis[list[i]]==dis[x]+1)
{
w=find(list[i],min(key[i],flow-used));
key[i]-=w; key[i^1]+=w; used+=w;
if (used==flow) return used;
}
if (!used) dis[x]=-1;
return used;
}
inline void dinic()
{
int tmp=0;
while (BFS())
{
for (int i=1;i<=n;i++) cur[i]=head[i];
tmp+=find(S,inf);
}
}
void dfs(int x)
{
dfn[x]=low[x]=++tot;
stack[++top]=x;
inset[x]=1;
for (int i=head[x];i;i=next[i])
if (key[i])
{
if (!dfn[list[i]])
{
dfs(list[i]);
low[x]=min(low[x],low[list[i]]);
}
else if (inset[list[i]]) low[x]=min(low[x],dfn[list[i]]);
}
if (low[x]==dfn[x])
{
int i=-1; scc++;
while (i!=x)
{
i=stack[top--];
inset[i]=0;
belong[i]=scc;
}
}
}
inline void tarjan()
{
for (int i=1;i<=n;i++) if (!dfn[i]) dfs(i);
}
int main()
{
n=read(); m=read(); S=read(); T=read();
for (int i=1;i<=m;i++)
{
int u=read(),v=read(),w=read();
insert(u,v,w); insert(v,u,0);
}
dinic();
tarjan();
for (int i=2;i<=cnt;i+=2)
if (key[i]) puts("0 0");
else
{
if (belong[from[i]]!=belong[list[i]]) printf("1 "); else printf("0 ");
if (belong[from[i]]==belong[S]&&belong[list[i]]==belong[T]) puts("1"); else puts("0");
}
return 0;
}