题解 Hack

传送门

  • 当出现形如「无向图上要求源汇点之间任意路径上只有一边被割的最小割」的限制时(确实不知道怎么抽象出模型了
    考虑一个最小割所形成的两个集合,观察样例可以发现一个割中的边有的是从S到T,有的是从T到S
    而不满足题述条件的情况就是存在从T返回S的流,这样一条路径上会被割多次
    于是不能存在这样的流,在跑最小割时将反向边设为正无穷即可
    这样一条从S到T的边的反向边肯定不会被割
    一条从T到S的边因为它的反向边是正无穷,所以最大流肯定会试图流满它反向边的流量,所以这条边也不会有流量
    注意要跑tarjan缩点特判源汇点连通的情况
    还要从源汇点分别dfs一次,只有都能dfs到的点才能保留,剩下的点也反向边设为inf的话可能导致源汇点直接由inf边连通
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
ll ans;
bool vis[N], vis1[N], vis2[N];
int dfn[N], low[N], bel[N], sta[N], tot, top, now, num;
int head[N], size=1, cur[N], dep[N], s, t;
struct edge{int to, next; ll val;}e[N<<1];
inline void add(int s, int t, int w) {e[++size]={t, head[s], w}; head[s]=size;}
#define live(u) (vis1[u]&&vis2[u])

bool bfs(int s, int t) {
	memset(dep, 0, sizeof(dep));
	queue<int> q;
	dep[s]=1; cur[s]=head[s];
	q.push(s);
	int u;
	while (q.size()) {
		u=q.front(); q.pop();
		for (int i=head[u],v; ~i; i=e[i].next) if (live(e[i].to))  {
			v = e[i].to;
			if (e[i].val&&!dep[v]) {
				dep[v]=dep[u]+1;
				cur[v]=head[v];
				if (v==t) return 1;
				q.push(v);
			}
		}
	}
	return 0;
}

ll dfs(int u, ll in) {
	if (u==t||!in) return in;
	ll rest=in, tem;
	for (int i=cur[u],v; ~i; cur[u]=i=e[i].next) if (live(e[i].to)) {
		v = e[i].to;
		if (e[i].val&&dep[v]==dep[u]+1) {
			tem=dfs(v, min(rest, e[i].val));
			if (!tem) dep[v]=0;
			rest-=tem;
			e[i].val-=tem;
			e[i^1].val+=tem;
			if (!rest) break;
		}
	}
	return in-rest;
}

void tarjan(int u) {
	dfn[u]=low[u]=++tot;
	sta[++top]=u;
	vis[u]=1;
	for (int i=head[u],v; ~i; i=e[i].next) if (e[i].val!=INF) {
		v = e[i].to;
		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]) {
		++num;
		do {
			vis[sta[top]]=0;
			bel[sta[top--]]=num;
		} while (sta[top+1]!=u);
	}
}

void dfs1(int u) {
	vis1[u]=1;
	for (int i=head[u],v; ~i; i=e[i].next) if (e[i].val!=INF) {
		v = e[i].to;
		if (!vis1[v]) dfs1(v);
	}
}

void dfs2(int u) {
	vis2[u]=1;
	for (int i=head[u],v; ~i; i=e[i].next) if (e[i].val==INF) {
		v = e[i].to;
		if (!vis2[v]) dfs2(v);
	}
}

signed main()
{
	n=read(); m=read();
	memset(head, -1, sizeof(head));
	s=1; t=n;
	for (int i=1,u,v,w; i<=m; ++i) {
		u=read()+1; v=read()+1; w=read();
		add(u, v, w); add(v, u, INF);
	}
	tarjan(s);
	if (bel[s]==bel[t]) {puts("-1"); return 0;}
	dfs1(s); dfs2(t);
	while (bfs(s, t)) ans+=dfs(s, INF);
	printf("%lld\n", ans);

	return 0;
}
posted @ 2021-12-23 21:31  Administrator-09  阅读(0)  评论(0编辑  收藏  举报