网络流在残量网络上的改图操作

Q: 网络流如果第一题和第二题就差少数边不一样,就比如说本来(1,2)容量为1,第二问(1,2)容量变成INF,这种情况可以直接在(1,2)间加一条边继续增广来求吗?
A: 可以 就加到残量网络上 就行了

那么费用流可以吗?
我觉得在最大流不变,费用改变的情况下是不可以的,因为

inline ll Dinic(int on) {
    ll res = 0, cost = 0;
    while (spfa(on)) {
        ll flow = dfs(S, inf);
        res += flow, cost += flow * dis[T];
    }
    return cost;
}

发现 \(flow\) 为 \(0\) 时,这里一乘,诶,没了

至于有没有更优美的写法,最近再思考思考这个问题

用一个简便的例子演示一下加到残量网络的操作

int main() {
    memset(head, -1, sizeof head);
    int n;
    S = 10, T = 11;
    add(S, 1, 1);
    add(S, 2, 1);

    add(1, 3, 1);
    add(2, 3, 1);

    add(3, T, 1);
    int m = cnt_edge - 2;
    cout << e[m].v << endl;
    
    cout << dinic() << endl;
    e[m].w = INF;
    cout << dinic() << endl;
}

输出

11
1
1

一开始流量为1,加边后又增广1,如果是统计答案记得要求和,因为每次Dinic返回的是本次增广多出来的流

对于费用流也同样:

signed main() {
    
    S = 10, T = 11;
    addflow(S, 1, 1, 1);
    addflow(S, 2, 1, 2);

    addflow(1, 3, 1, 1);
    addflow(2, 3, 1, 2);

    addflow(3, T, 1, 1);
    int m = cnt_edge - 1;
    cout << m << " " << e[m].to << endl;

    cout << Dinic(-1) << endl;
    e[m].flow = 0x3f3f3f3f;
    cout << Dinic(-1) << endl;
}

写的是最大费用流,于是先增广了费用高的那一条,第二次增广了费用小的那一条,因此
output

5
3

最大流完整代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 500 + 5;
const int M = N;
const int INF = 0x3f3f3f3f;
struct edge {
    int v, w, to;
} e[M * 2];
int pre[N], cnt_edge, dep[N];
int S, T, z, head[N], sum;
int n, m, q[N], cur[N];
void add(int u, int v, int w) {
    e[cnt_edge] = {v, w, head[u]};
    head[u] = cnt_edge++;
    e[cnt_edge] = {u, 0, head[v]};
    head[v] = cnt_edge++;
}
bool bfs() {
    for (int i = 0; i <= T; i++) dep[i] = 0;
    dep[S] = 1;
    int l = 0, r = 1;
    q[r] = S;
    while (l < r) {
        int u = q[++l];
        for (int i = head[u]; i != -1; i = e[i].to) {
            int v = e[i].v;
            if (!dep[v] && e[i].w) dep[v] = dep[u] + 1, q[++r] = v;
        }
    }
    return dep[T];
}
int dfs(int u, int mi) {
    int res = 0;
    if (mi == 0 || u == T) return mi;
    for (int &i = cur[u]; i != -1; i = e[i].to) {
        int v = e[i].v;
        if (dep[u] + 1 == dep[v] && e[i].w) {
            int minn = dfs(v, min(mi - res, e[i].w));
            e[i].w -= minn;
            e[i ^ 1].w += minn;
            res += minn;
            if (res == mi) return res;
        }
    }
    if (res == 0) dep[u] = 0;
    return res;
}
int dinic() {
    ll res = 0;
    while (bfs()) {
        memcpy(cur, head, sizeof(head));
        //    cout<<res<<endl;
        res += dfs(S, INF);
    }
    return res;
}
int main() {
    memset(head, -1, sizeof head);
    int n;
    S = 10, T = 11;
    add(S, 1, 1);
    add(S, 2, 1);

    add(1, 3, 1);
    add(2, 3, 1);

    add(3, T, 1);
    int m = cnt_edge - 2;
    cout << e[m].v << endl;
    
    cout << dinic() << endl;
    e[m].w = INF;
    cout << dinic() << endl;
}
费用流完整代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <vector>
#define endl '\n'
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
#define P pair<int, int>
using namespace std;

#define int long long
typedef long long ll;
const int maxn = 20 * 40 * 2 * 2 + 5;
const ll inf = 1e18;
int n1, n2, cnt_edge = 1, S, T;
int a1[maxn], a2[maxn], head[maxn];
ll dis[maxn];
bool vis[maxn];
struct edge {
    int to, nxt;
    ll flow, cost;
} e[(maxn * maxn) << 2];
inline void add(int u, int v, ll w, ll c) {
    e[++cnt_edge].nxt = head[u];
    head[u] = cnt_edge;
    e[cnt_edge].to = v;
    e[cnt_edge].flow = w;
    e[cnt_edge].cost = c;
}
inline void addflow(int u, int v, ll w, ll c) {
    add(u, v, w, c);
    add(v, u, 0, -c);
    // if(u + 1 == v)
    // cout << "add: "<<u << " " << v << " "<<cnt_edge<<endl;
}
inline bool spfa(int on) {
    memset(vis, 0, sizeof(vis));
    if (on == 1)
        for (int i = 0; i <= T; i++) dis[i] = inf;
    else
        for (int i = 0; i <= T; i++) dis[i] = -inf;

    queue<int> q;
    q.push(S);
    dis[S] = 0;
    vis[S] = 1;
    while (!q.empty()) {
        int x = q.front();
        q.pop();
        vis[x] = 0;
        for (int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            // cout << "->" << y << endl;
            if ((on == 1 && e[i].flow && dis[y] > dis[x] + e[i].cost) ||
                (on == -1 && e[i].flow && dis[y] < dis[x] + e[i].cost)) {
                dis[y] = dis[x] + e[i].cost;
                if (!vis[y]) q.push(y), vis[y] = 1;
            }
        }
    }
    if (on == 1)
        return dis[T] != inf;
    else
        return dis[T] != -inf;
}
ll dfs(int x, ll lim) {
    vis[x] = 1;
    if (x == T || lim <= 0) return lim;
    ll res = lim;
    for (int i = head[x]; i; i = e[i].nxt) {
        int y = e[i].to;
        if (dis[y] != dis[x] + e[i].cost || e[i].flow <= 0 || vis[y]) continue;
        ll tmp = dfs(y, min(res, e[i].flow));
        res -= tmp;
        e[i].flow -= tmp;
        e[i ^ 1].flow += tmp;
        if (res <= 0) break;
    }
    return lim - res;
}
inline ll Dinic(int on) {
    ll res = 0, cost = 0;
    while (spfa(on)) {
        ll flow = dfs(S, inf);
        res += flow, cost += flow * dis[T];
        // cout << "flow " << flow << " " << dis[T] << endl;
    }
    return cost;
}
int val[maxn][maxn];
int id(int x, int y, int in) {
    return 2 * ((n1 * 2 + x - 2) * (x - 1) / 2 + y - 1) + in;
}
vector<int> edge[3];
//拆点之间的边
//除S T 的相邻的边
// T相邻边

struct debug { int u, v, id1, id2; };
signed main() {
    
    S = 10, T = 11;
    addflow(S, 1, 1, 1);
    addflow(S, 2, 1, 2);

    addflow(1, 3, 1, 1);
    addflow(2, 3, 1, 2);

    addflow(3, T, 1, 1);
    int m = cnt_edge - 1;
    // cout << m << " " << e[m].to << endl;

    cout << Dinic(-1) << endl;
    e[m].flow = 0x3f3f3f3f;
    cout << Dinic(-1) << endl;
    return 0;
}
上一篇:CF1051F The Shortest Statement 题解


下一篇:Dijkstra算法详解