【BZOJ1797】最小割(AHOI2009)-最小割+SCC
测试地址:最小割
做法:本题需要用到最小割+SCC。
首先,根据最大流和最小割的关系不难看出,跑完最大流后没有满流的边都不可能出现在最小割中。
那么对于剩下的边,如果它的两个端点在残余网络中(注意,残余网络是带反向边的)在同一个强连通分量内,很显然它也不可能出现在最小割中(因为割掉这条边没什么意义),否则它就可能出现在最小割中。
而对于一条边,如果它的两个端点在残余网络中分别和源点和汇点在同一个强连通分量中,那么它就一定出现在最小割中,因为一旦它容量变大,我们就可以增广出新的最大流,矛盾。
得出上述的结论之后,我们就可以按照上面的条件判定每条边属于哪种情况了。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=(ll)1000000000*(ll)1000000000;
int n,m,S,T,first[4010]={0},tot=1;
int lvl[4010],cur[4010],h,t,q[4010];
int st[4010],belong[4010],top=0,totscc=0,dfn[4010],low[4010],tim=0;
bool vis[4010]={0},inst[4010]={0};
struct edge
{
int v,next;
ll f;
}e[120010];
void insert(int a,int b,ll f)
{
e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,first[a]=tot;
e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,first[b]=tot;
}
bool makelevel()
{
for(int i=1;i<=n;i++)
lvl[i]=-1,cur[i]=first[i];
h=t=1;
q[1]=S;
lvl[S]=0;
while(h<=t)
{
int v=q[h++];
for(int i=first[v];i;i=e[i].next)
if (e[i].f&&lvl[e[i].v]==-1)
{
lvl[e[i].v]=lvl[v]+1;
q[++t]=e[i].v;
}
}
return lvl[T]!=-1;
}
ll maxflow(int v,ll maxf)
{
ll ret=0,f;
if (v==T) return maxf;
for(int i=cur[v];i;i=e[i].next)
{
if (e[i].f&&lvl[e[i].v]==lvl[v]+1)
{
f=maxflow(e[i].v,min(maxf-ret,e[i].f));
ret+=f;
e[i].f-=f;
e[i^1].f+=f;
if (ret==maxf) break;
}
cur[v]=i;
}
if (!ret) lvl[v]=-1;
return ret;
}
void dinic()
{
while(makelevel()) maxflow(S,inf);
}
void tarjan(int v)
{
vis[v]=inst[v]=1;
st[++top]=v;
dfn[v]=low[v]=++tim;
int now=top;
for(int i=first[v];i;i=e[i].next)
if (e[i].f)
{
if (!vis[e[i].v])
{
tarjan(e[i].v);
low[v]=min(low[v],low[e[i].v]);
}
else if (inst[e[i].v]) low[v]=min(low[v],dfn[e[i].v]);
}
if (dfn[v]==low[v])
{
totscc++;
for(int i=now;i<=top;i++)
{
belong[st[i]]=totscc;
inst[st[i]]=0;
}
top=now-1;
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&S,&T);
for(int i=1;i<=m;i++)
{
int a,b;
ll c;
scanf("%d%d%lld",&a,&b,&c);
insert(a,b,c);
}
dinic();
for(int i=1;i<=n;i++)
if (!vis[i]) tarjan(i);
for(int i=1;i<=m;i++)
{
if (e[i<<1].f) {printf("0 0\n");continue;}
if (belong[e[i<<1].v]!=belong[e[i<<1|1].v]) printf("1 ");
else {printf("0 0\n");continue;}
if (belong[e[i<<1].v]==belong[T]&&belong[e[i<<1|1].v]==belong[S])
printf("1\n");
else printf("0\n");
}
return 0;
}