浅谈有源汇上下界最小流

柔情痞子 提交于 2020-03-03 13:43:13

某个著名 oj 的帖子是这样的

我们可以照无源无汇的可行流,来进行改造,为了照无源无汇的跑,所以要加一条 t -> s ,up = inf, low = 0 的边

此题正常的操作就是先跑 sstt 的可行流,现在的 实际可行流 不是我们的 \(\sum_{in[i]>0} in[i]\) ,而是 我们建的那条边的流量 自己翻翻定义就好了。

然后,据 newcoder 说的,我们从 ts 反跑最大流 这是为了减去能减的附加流,注意除了 st 之外的天此时都流量平衡,所以我们可以减去这个最大流

ps:因为 s,t 不用平衡

但是这么跑有的会崩。。

就是说,最大流的依据就是找增广路 ,而算导上对增广路给出的明确定义 ,详情可以参考我写的博客

既然增广路已经明确是从 s->t 的,所以在 hack 数据上会有问题 ,这是因为 从 st 一个环,就会造成 st 会有平衡的问题,就是说,从 t 也要流出,从 s 流入

hack数据

3 3 1 3
1 2 1 100
2 3 1 100
3 1 1 100

而跑最大流的依据就是 st 流量不平衡。。

所以有问题。。

然后,通过遐想,我想到了一种方法,就是说,可以通过转化 st 来解决

我们这么搞,建一个 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

这是正确程序

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!