我们可以照无源无汇的可行流,来进行改造,为了照无源无汇的跑,所以要加一条 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