我们可以照无源无汇的可行流,来进行改造,为了照无源无汇的跑,所以要加一条 t -> s ,up = inf, low = 0 的边
此题正常的操作就是先跑 ss 到 tt 的可行流,现在的 实际可行流 不是我们的 \(\sum_{in[i]>0} in[i]\) ,而是 我们建的那条边的流量 自己翻翻定义就好了。
然后,据 newcoder 说的,我们从 t 向 s 反跑最大流 这是为了减去能减的附加流,注意除了 s 和 t 之外的天此时都流量平衡,所以我们可以减去这个最大流
ps:因为 s,t 不用平衡。
但是这么跑有的会崩。。
就是说,最大流的依据就是找增广路 ,而算导上对增广路给出的明确定义 ,详情可以参考我写的博客
既然增广路已经明确是从 s->t 的,所以在 hack 数据上会有问题 ,这是因为 从 s 和 t 一个环,就会造成 s 和 t 会有平衡的问题,就是说,从 t 也要流出,从 s 流入
hack数据
3 3 1 3 1 2 1 100 2 3 1 100 3 1 1 100
而跑最大流的依据就是 s 和 t 流量不平衡。。
所以有问题。。
然后,通过遐想,我想到了一种方法,就是说,可以通过转化 s 与 t 来解决
我们这么搞,建一个 sss ttt 分别于 s, t 建边 然后,把 sss 当作 s ,ttt 当作 t 即可 low = 0,up = inf,然后正常跑。就行了
至于正确性吗,我们就是说,通过新建源汇结点,把原本的平衡和不平衡条件 都完美的解决了,又转化为了没有环的
#include <cstdio> #include <cstring> #include <queue> #define inf 1e10 #define sz 666666 #define get() getchar() #define fake int typedef long long ll; typedef long double ldb; using namespace std; #define int ll int read() { int x = 0; char ch = get(); while(ch < '0' || ch > '9') ch = get(); while(ch <= '9' && ch >= '0') { x = (x << 1) + (x << 3) + (ch - '0'); ch = get(); } return x; } const int Maxn = 50009, Maxm = 125003 * 3; int n, m, s, t, in[Maxn], h[Maxn], cnt, ss, tt, sum, maxflow, dep[Maxn], gap[Maxn], cur[Maxn], sss, ttt; struct Edge{ int fr, to, lac, flow; void insert(int x, int y, int z){ fr = x;to = y; flow = z; lac = h[x]; h[x] = cnt++; return ; } }edge[Maxm]; void add_edge(int up, int low, int v, int u){ in[u] -= low, in[v] += low; edge[cnt].insert(u, v, up - low); edge[cnt].insert(v, u, 0); return ; } void bfs(int s, int t) { memset(dep, -1, sizeof dep); memset(gap, 0, sizeof gap); queue <int> q; q.push(t); gap[0] = 1; dep[t] = 0; if(s == 0) while(!q.empty()) { int fr = q.front(); q.pop(); for(int i = h[fr]; i!=-1; i=edge[i].lac){ int to = edge[i].to; if(dep[to] != -1) continue; dep[to] = dep[fr] + 1; gap[dep[to]]++; q.push(to); } } else while(!q.empty()) { int fr = q.front(); q.pop(); for(int i = h[fr]; i!=-1; i=edge[i].lac){ int to = edge[i].to; if(dep[to] != -1 || to == ss || to == tt) continue; dep[to] = dep[fr] + 1; gap[dep[to]]++; q.push(to); } } } int dfs(int u, int min1, int s ,int t){ if(u == t) return min1; int sum = min1; for(int i = cur[u]; i != -1; i = edge[i].lac) { int to = edge[i].to; if(! edge[i].flow || dep[to] + 1 != dep[u] || dep[to] == -1) continue; cur[u] = i; int ret = dfs(to, min(edge[i].flow, sum), s ,t); sum -= ret; edge[i].flow -= ret; edge[i ^ 1].flow += ret; if(! sum) return min1; } if(--gap[dep[u]] == 0) dep[s] = n + 4; gap[++dep[u]]++; return min1 - sum; } void ISAP(int s, int t) { bfs(s, t); while(dep[s] == -1 || dep[s] < n + 4) { memcpy(cur, h, sizeof cur); maxflow += dfs(s, 0x3f3f3f3f, s, t); } return ; } #undef int int main() { freopen("test.in", "r", stdin); n = read();m = read();s = read();t = read(); sss = n + 2, ttt = n + 3; memset(h, -1, sizeof h); for(int i = 1; i <= m; ++i) add_edge(read(), read(), read(), read()); ss = 0, tt = n + 1; for(int i = 1; i <= n; ++i) if(in[i] > 0) sum+=in[i], add_edge(in[i], 0, i, ss); else if(in[i] < 0) add_edge(-in[i], 0, tt, i); add_edge(inf, 0, s, sss); add_edge(inf, 0, ttt, t); add_edge(inf, 0, sss, ttt); ISAP(ss, tt); if(maxflow != sum) { printf("please go home to sleep"); return 0; } maxflow = 0; ll maxflow1 = edge[cnt - 1].flow; h[sss] = edge[h[sss]].lac; h[ttt] = edge[h[ttt]].lac; ISAP(ttt, sss); printf("%lld", maxflow1 - maxflow); return 0; } #undef sz #undef fake #undef get #undef inf
这是正确程序
来源:https://www.cnblogs.com/zhltao/p/12401622.html