1797: [Ahoi2009]Mincut 最小割
分析:
题意为:问一条边是否可能存在于最小割中,是否一定存在于最小割中。
首先最小割的边一定是满流的边。且这条边点两个端点u.v中,至少一个与S或T联通。而且在残量网络中u->v没有增广路。如果存在增广路,那么会使最小割的增加。这条增广路会和u->v的反向边构成强连通分量。所以一条边可能存在于最小割中,要满足:满流, 残量网络中u,v不属于一个强连通分量。
那么第二问就是要求S一定可以到u,v一定可以到T。此时如果存在这样的一条路径,会和S->u的反向边构成强连通分量,于是一条边一定存在于最小割中,满足:满流,残量网络中S和u属于同一个强连通分量,v和T属于同一个强连通分量。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<queue> #include<vector> #include<set> #include<map> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 4005, INF = 1e9; struct Edge { int fr, to, nxt, cap; } e[200005]; int head[N], cur[N], dis[N], q[N], low[N], dfn[N], sk[N], bel[N]; int Index, top, S, T, En = 1, n, m, cnt; bool vis[N]; inline void add_edge(int u,int v,int w) { ++En; e[En].fr = u, e[En].to = v, e[En].cap = w, e[En].nxt = head[u]; head[u] = En; ++En; e[En].fr = v, e[En].to = u, e[En].cap = 0, e[En].nxt = head[v]; head[v] = En; } bool bfs() { for (int i = 1; i <= n; ++i) cur[i] = head[i], dis[i] = -1; int L = 1, R = 0; q[++R] = S; dis[S] = 0; while (L <= R) { int u = q[L ++]; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (dis[v] == -1 && e[i].cap > 0) { dis[v] = dis[u] + 1; q[++R] = v; if (v == T) return true; } } } return false; } int dfs(int u,int flow) { if (u == T) return flow; int used = 0, tmp; for (int &i = cur[u]; i; i = e[i].nxt) { int v = e[i].to; if (dis[v] == dis[u] + 1 && e[i].cap > 0) { tmp = dfs(v, min(flow - used, e[i].cap)); if (tmp > 0) { used += tmp; e[i].cap -= tmp; e[i ^ 1].cap += tmp; if (used == flow) break; } } } if (used != flow) dis[u] = -1; return used; } int dinic() { int ans = 0; while (bfs()) ans += dfs(S, INF); return ans; } void tarjan(int u) { low[u] = dfn[u] = ++Index; sk[++top] = u, vis[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (e[i].cap) { if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (vis[v]) low[u] = min(low[u], dfn[v]); } } if (low[u] == dfn[u]) { ++cnt; do { bel[sk[top]] = cnt; vis[sk[top]] = false; top --; } while (sk[top + 1] != u); } } int main() { n = read(), m = read(); S = read(), T = read(); for (int i = 1; i <= m; ++i) { int u = read(), v = read(), w = read(); add_edge(u, v, w); } dinic(); for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i); for (int i = 2; i <= En; i += 2) { if (e[i].cap > 0) puts("0 0"); else { printf(bel[e[i].fr] != bel[e[i].to] ? "1 " : "0 "); puts(bel[e[i].fr] == bel[S] && bel[e[i].to] == bel[T] ? "1" : "0"); } } return 0; }