BZOJ 1797: [Ahoi2009]Mincut 最小割
一个很好用的结论:
对残余网络的S与T分别作bfs,得出每个点是否和S/T在同一连通块中
一条x到y的单向边
满足1:当x,y不同时属于S/T连通块且该边满流
满足2:当x,y分别属于S与T连通块且该边满流
CODE:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define maxn 4010
#define maxm 60100
struct edges{
int to,next,cap;
}edge[maxm*2];
int s,t,next[maxn],l,n,m;
void addedge(int x,int y,int z){
l++;
edge[l*2]=(edges){y,next[x],z};next[x]=l*2;
edge[l*2+1]=(edges){x,next[y],0};next[y]=l*2+1;
}
#define inf 0x7fffffff
int gap[maxn],h[maxn],p[maxn];
int sap(int u,int flow){
if (u==t) return flow;
int cnt=0;
for (int i=p[u];i;i=edge[i].next)
if (edge[i].cap&&h[edge[i].to]+1==h[u]) {
int cur=sap(edge[i].to,min(flow-cnt,edge[i].cap));
edge[i].cap-=cur;edge[i^1].cap+=cur;
p[u]=i;
if ((cnt+=cur)==flow) return flow;
}
if (!(--gap[h[u]])) h[s]=n;
gap[++h[u]]++;
p[u]=next[u];
return cnt;
}
int maxflow(){
memset(gap,0,sizeof(gap));
memset(h,0,sizeof(h));
for (int i=1;i<=n;i++) p[i]=next[i];
gap[0]=n;
int flow=0;
while (h[s]<n) flow+=sap(s,inf);
return flow;
}
queue<int> q;
int ans[2][maxm];
bool b[maxm][2];
int bfs(int x,int y) {
q.push(x);
while (!q.empty()) {
int u=q.front();q.pop();
b[u][y]=1;
for (int i=next[u];i;i=edge[i].next)
if (edge[i^y].cap&&!b[edge[i].to][y]) q.push(edge[i].to);
}
return 0;
}
int main(){
scanf("%d%d%d%d",&n,&m,&s,&t);
for (int i=1;i<=m;i++) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
}
maxflow();
bfs(s,0);bfs(t,1);
for (int i=1;i<=l;i++) {
if (!edge[i*2].cap){
int u=edge[i*2].to,v=edge[i*2+1].to;
if ((b[u][0]&&b[v][1])||(b[u][1]&&b[v][0])) ans[1][i]=1;
if (!((b[u][0]&&b[v][0])||(b[u][1]&&b[v][1]))) ans[0][i]=1;
}
}
for (int i=1;i<=m;i++) printf("%d %d\n",ans[0][i],ans[1][i]);
return 0;
}