[BZOJ1797][Ahoi2009]Mincut 最小割 && 最小割+强连通

先跑一遍最大流 然后在残余网络里面跑强连通 跑完过后对于每一条满流边的两个端点u, v

检验他们所在的强连通分量 

若SCC[u] != SCC[v] 则这条边至少存在于一个最小割方案中

若SCC[u] != SCC[v] 并且 SCC[u] == SCC[S] && SCC[v] == SCC[T]  那么这一条边一定在任何一个最小割方案中

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define SF scanf
#define PF printf
using namespace std;
typedef long long LL;
const int MAXN = 4000;
const int MAXM = 60000;
const int INF = 0x3f3f3f3f;
int n, m, S, T;
int dfn[MAXN+10], low[MAXN+10], dcnt, scc, SCC[MAXN+10];
int sta[MAXN+10], top;
int val[MAXM+10];
struct Node {
	int u, v, c, next, id;
};
struct ISAP {
	int gap[MAXN+10], d[MAXN+10];
	int adj[MAXN+10], ecnt;
	Node Edge[MAXM*2+10];
	int n, s, t;
	void init() {
		memset(adj, -1, sizeof(adj));
	}
	void addedge(int u, int v, int c, int id) {
		Node &e = Edge[ecnt];
		e.v = v; e.u = u; e.c = c; e.id = id; 
		e.next = adj[u]; adj[u] = ecnt++;
	}
	void add(int u, int v, int c, int id) {
		addedge(u, v, c, id);
		addedge(v, u, 0, id);
	}
	void init_dis() {
		queue <int> q;
		memset(d, 0, sizeof(d));
		memset(gap, 0, sizeof(gap));
		q.push(t);
		while(!q.empty()) {
			int u = q.front(); q.pop();
			gap[d[u]]++;
			for(int i = adj[u]; ~i; i = Edge[i].next) {
				int v = Edge[i].v;
				if(!d[v] && v != t) d[v] = d[u] + 1, q.push(v);
			}
		}
	}
	int aug(int u, int inc) {
		int Inc = 0, mindis = n-1;
		if(u == t) return inc;
		for(int i = adj[u]; ~i; i = Edge[i].next) {
			Node &e = Edge[i];
			int v = e.v, c = e.c;
			if(c) {
				if(d[v] == d[u] - 1) {
					int del = min(c, inc - Inc);
					del = aug(v, del);
					Inc += del;
					Edge[i].c -= del;
					Edge[i^1].c += del;
					if(d[s] >= n) return Inc;
					if(inc == Inc) return inc;
				}
				mindis = min(mindis, d[v]);
			}
		}
		if(!Inc) {
			gap[d[u]]--;
			if(gap[d[u]] == 0) d[s] = n;
			d[u] = mindis + 1;
			gap[d[u]]++;
		}
		return Inc;
	}
	int Maxflow(int _s, int _t, int _n) {
		s = _s; t = _t; n = _n;
		int ret = 0;
		init_dis();
		while(d[s] < n) ret += aug(s, INF);
		return ret;
	}
	void dfs(int u) {
		low[u] = dfn[u] = ++dcnt;
		sta[++top] = u;
		for(int i = adj[u]; ~i; i = Edge[i].next) {
			Node &e = Edge[i];
			int v = e.v, c = e.c;
			if(!c) continue ;
			if(!dfn[v]) { 
				dfs(v); low[u] = min(low[v], low[u]);
			}
			else if(!SCC[v]) low[u] = min(low[u], dfn[v]);
		}
		if(low[u] == dfn[u]) {
			int x;
			scc++;
			do {
				x = sta[top--];
				SCC[x] = scc;
			} while(x != u);
		}
	}
	void build() {
		for(int u = 1; u <= n; u++)
			for(int i = adj[u]; ~i; i = Edge[i].next) {
				Node &e = Edge[i];
				int v = e.v, c = e.c;
				if((i & 1) == 0 && c == 0) {
					if(SCC[u] != SCC[v]) {
						if(SCC[u] == SCC[S] && SCC[v] == SCC[T])
							val[e.id] = 2;
						else val[e.id] = 1;
					}
				}
			}
	}
} sap;
void find_scc() {
	for(int i = 1; i <= n; i++) if(!dfn[i]) sap.dfs(i);
	sap.build();
}
int main() {
	sap.init();
	SF("%d%d%d%d", &n, &m, &S, &T);
	for(int i = 1; i <= m; i++) {
		int u, v, c; 
		SF("%d%d%d", &u, &v, &c);
		sap.add(u, v, c, i);
	}
	sap.Maxflow(S, T, n);
	find_scc();
	for(int i = 1; i <= m; i++)
		if(val[i] == 2) puts("1 1");
		else if(val[i] == 1) puts("1 0");
		else puts("0 0");
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值