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 ",ans[0][i],ans[1][i]);

return 0;

}


原文地址:https://www.cnblogs.com/New-Godess/p/4348903.html