传送门
- 当出现形如「无向图上要求源汇点之间任意路径上只有一边被割的最小割」的限制时(
确实不知道怎么抽象出模型了:
考虑一个最小割所形成的两个集合,观察样例可以发现一个割中的边有的是从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;
}