网络流与线性规划24题(写了一半,先鸽下了……)

本文详细介绍了网络流算法在解决实际问题中的应用,包括最大流、最小割、最大匹配等经典问题,并给出了多个实例,如飞行员配对、试题库分配、运输问题和分配问题等,通过具体代码实现展示了网络流算法的灵活性和实用性。
摘要由CSDN通过智能技术生成

Network-flows

Ford-Fulkerson算法

typedef long long ll;

const int N = 1e5 + 10;

int head[N], to[N], nex[N], flow[N], cnt;

int vis[N], n, m, s, t;

void add(int x, int y, int w) {
    to[cnt] = y;
    nex[cnt] = head[x];
    flow[cnt] = w;
    head[x] = cnt++;
}

ll dfs(int rt, ll now) {
    if(rt == t) return now;
    vis[rt] = 1;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(!vis[to[i]] && flow[i] > 0) {
            ll cur = dfs(to[i], min(now, 1ll * flow[i]));
            if(cur != -1) {
                flow[i] -= cur;
                flow[i ^ 1] += cur;
                return cur;
            }
        }
    }
    return -1;
}

ll solve() {
    ll ans = 0, cur;
    while(true) {
        cur = dfs(s, 0x3f3f3f3f3f3f3f3f);
        if(cur == -1) return ans;
        ans += cur;
        memset(vis, 0, sizeof vis);
    }
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head);
    n = read(), m = read(), s = read(), t = read();
    for(int i = 1; i <= m; i++) {
        int x = read(), y = read(), w = read();
        add(x, y, w);
        add(y, x, 0);
    }
    printf("%lld\n", solve());
    return 0;
}

Edmond-Karp

typedef long long ll;

const int N = 1e5 + 10;

ll head[N], to[N], nex[N], flow[N], cnt;

ll last[N], n, m, s, t;

ll flo[N];

void add(int x, int y, int w) {
    to[cnt] = y;
    nex[cnt] = head[x];
    flow[cnt] = w;
    head[x] = cnt++;
}

bool bfs() {
    queue<int> q;
    q.push(s);
    flo[s] = 0x3f3f3f3f3f3f3f3f;
    memset(last, -1, sizeof last);
    while(q.size()) {
        int temp = q.front();
        q.pop();
        if(temp == t) {
            break;
        }
        for(int i = head[temp]; ~i; i = nex[i]) {
            if(last[to[i]] == -1 && flow[i]) {
                last[to[i]] = i;
                flo[to[i]] = min(flo[temp], 1ll * flow[i]);
                q.push(to[i]);
            }
        }
    }
    return last[t] != -1;
}

ll solve() {
    ll ans = 0;
    while(bfs()) {
        ans += flo[t];
        for(int i = t; i != s; i = to[last[i] ^ 1]) {
            flow[last[i]] -= flo[t];
            flow[last[i] ^ 1] += flo[t];
        }
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head);
    n = read(), m = read(), s = read(), t = read();
    for(int i = 1; i <= m; i++) {
        int x = read(), y = read(), w = read();
        add(x, y, w);
        add(y, x, 0);
    }
    printf("%lld\n", solve());
    return 0;
}

Dinic

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10, inf = 0x3f3f3f3f;

struct max_flow {

    int head[N], to[N], nex[N], cap[N], cnt;

    int s, t, dep[N], x[N], y[N], f[N];

    void init() {
        memset(head, -1, sizeof head), cnt = 0;
    }

    void Add(int x, int y, int c) {
        to[cnt] = y;
        nex[cnt] = head[x];
        cap[cnt] = c;
        head[x] = cnt++;
    }

    void add(int x, int y, int c) {
        Add(x, y, c);
        Add(y, x, 0);
    }

    bool bfs() {
        queue<int> q;
        memset(dep, -1, sizeof dep);
        dep[s] = 0;
        q.push(s);
        while(q.size()) {
            int u = q.front();
            q.pop();
            for(int i = head[u]; ~i; i = nex[i]) {
                if(dep[to[i]] == -1 && cap[i]) {
                    q.push(to[i]);
                    dep[to[i]] = dep[u] + 1;
                }
            }
        }
        return dep[t] != -1;
    }

    int dfs(int rt, int flow) {
        if(rt == t) return flow;
        int res = flow;
        for(int i = head[rt]; ~i; i = nex[i]) {
            if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
                int temp = dfs(to[i], min(res, cap[i]));
                if(temp == 0) dep[to[i]] = -1;
                res -= temp;
                cap[i] -= temp;
                cap[i ^ 1] += temp;
            }
            if(res == 0) break;
        }
        return flow - res;
    }

    int Dinic() {
        int ans = 0;
        while(bfs()) {
            ans += dfs(s, inf);
        }
        return ans;
    }

    // void print(int rt) {
    //     for(int i = head[rt]; ~i; i = nex[i]) {
    //         if(cap[i] || to[i] == s || to[i] == rt + m) continue;
    //         printf(" %d", to[i] - m);
    //         print(to[i] - m);
    //         return ;
    //     }
    // }
}dinic;

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    return 0;
}

Mcmf

Spfa

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef pair<int, int> pii;

const int N = 5e5 + 10, inf = 0x3f3f3f3f;

struct min_cost_max_flow {
    int head[N], cap[N], to[N], nex[N], value[N], cnt;

    int s, t, dis[N], vis[N], flow[N], pre[N];

    void init() {
        memset(head, -1, sizeof head), cnt = 0;
    }

    void Add(int x, int y, int w, int c) {
        to[cnt] = y;
        nex[cnt] = head[x];
        value[cnt] = w;
        cap[cnt] = c;
        head[x] = cnt++;
    }

    void add(int x, int y, int w, int c) {
        Add(x, y, w, c);
        Add(y, x, -w, 0);
    }

    bool spfa() {
        queue<int> q;
        memset(dis, 0x3f, sizeof dis);
        memset(vis, 0, sizeof vis);
        q.push(s), dis[s] = 0, vis[s] = 1;
        flow[s] = 1 << 30;
        while(q.size()) {
            int rt = q.front();
            q.pop(), vis[rt] = 0;
            for(int i = head[rt]; ~i; i = nex[i]) {
                if(cap[i] && dis[to[i]] > dis[rt] + value[i]) {
                    dis[to[i]] = dis[rt] + value[i];
                    flow[to[i]] = min(flow[rt], cap[i]);
                    pre[to[i]] = i;
                    if(!vis[to[i]]) {
                        vis[to[i]] = 1;
                        q.push(to[i]);
                    }
                }
            }
        }
        return dis[t] != 0x3f3f3f3f;
    }

    pii Mcmf() {
        int res = 0, ans = 0;
        while(spfa()) {
            int cur = flow[t];
            res += cur, ans += dis[t] * cur;
            int now = t;
            while(now != s) {
                cap[pre[now]] -= cur;
                cap[pre[now] ^ 1] += cur;
                now = to[pre[now] ^ 1];
            }
        }
        return make_pair(res, ans);
    }
}mcmf;

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    return 0;
}

Dijkstra

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> pii;

const int N = 5e3 + 10, inf = 0x3f3f3f3f;

struct edge {
    int to, capacity, cost, rev;
    edge() {}
    edge(int to = 0, int _capacity = 0, int _cost = 0, int _rev = 0) :to(to), capacity(_capacity), cost(_cost), rev(_rev) {}
};
struct Min_Cost_Max_Flow {
    
    int V, s, t, H[N + 5], dis[N + 5], PreV[N + 5], PreE[N + 5];
    
    vector<edge> G[N + 5];
    
    void init(int n) {
        V = n;
        for (int i = 0; i <= V; ++i)G[i].clear();
    }

    void add(int from, int to, int cost, int cap) {
        G[from].push_back(edge(to, cap, cost, G[to].size()));
        G[to].push_back(edge(from, 0, -cost, G[from].size() - 1));
    }

    pii mcmf() {
        int res = 0, f = inf, flow = 0; fill(H, H + 1 + V, 0);
        while (f) {
            priority_queue <pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>> > q;
            fill(dis, dis + 1 + V, inf);
            dis[s] = 0; q.push(pair<int, int>(0, s));
            while (!q.empty()) {
                pair<int, int> now = q.top(); q.pop();
                int v = now.second;
                if (dis[v] < now.first)continue;
                for (int i = 0; i < G[v].size(); ++i) {
                    edge& e = G[v][i];
                    if (e.capacity > 0 && dis[e.to] > dis[v] + e.cost + H[v] - H[e.to]) {
                        dis[e.to] = dis[v] + e.cost + H[v] - H[e.to];
                        PreV[e.to] = v;
                        PreE[e.to] = i;
                        q.push(pair<int, int>(dis[e.to], e.to));
                    }
                }
            }
            if (dis[t] == inf)break;
            for (int i = 0; i <= V; ++i)H[i] += dis[i];
            int d = f;
            for (int v = t; v != s; v = PreV[v])d = min(d, G[PreV[v]][PreE[v]].capacity);
            f -= d; flow += d; res += d*H[t];
            for (int v = t; v != s; v = PreV[v]) {
                edge& e = G[PreV[v]][PreE[v]];
                e.capacity -= d;
                G[v][e.rev].capacity += d;
            }
        }
        return make_pair(flow, res);
    }
}mcmf;

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    return 0;
}

P2756 飞行员配对方案问题(二分图匹配)

二分图匹配问题然后输出匹配方案。

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, dep[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = 0;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head);
    scanf("%d %d", &m, &n);
    cnt = 0, s = 0, t = n + 1;
    for(int i = 1; i <= m; i++) {
        add(s, i, 1);
    }
    for(int i = m + 1; i <= n; i++) {
        add(i, t, 1);
    }
    int tot = cnt;
    int x, y;
    while(scanf("%d %d", &x, &y) && x != -1) {
        add(x, y, 1); 	
    }
    int ans = Dinic();
    printf("%d\n", ans);
    for(int i = tot; i < cnt; i += 2) {
        if(cap[i] == 0 && cap[i ^ 1] == 1) {
            printf("%d %d\n", to[i ^ 1], to[i]);
        }
    }
    return 0;
}

P5039 [SHOI2010]最小生成树

我们要使 a − b a-b ab出现在最小生成树集合中那么,必然有 a − > b a -> b a>b的所有路径中,每个路径中一定有一条边是大于 a − b a-b ab边的权值的,

对于每种操作,我们可以看作对选定的边进行 + 1操作,所以我们考虑如何将这个问题转化为网络流模型,

首先对于边权大于w[lab]的边是一定没有影响的,我们考虑边权小于w[a, b]的情况,

我们可以考虑用 w [ l a b ] − w [ n o w ] + 1 w[lab] - w[now] + 1 w[lab]w[now]+1 n o w a , n o w b now_a, now_b nowa,nowb两点间的流量的,然后跑一遍 l a − > l b l_a -> l_b la>lb的最小割就行了,

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, l, dep[N], x[N], y[N], f[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = 0;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head);
    scanf("%d %d %d", &n, &m, &l);
    for(int i = 1; i <= m; i++) {
        scanf("%d %d %d", &x[i], &y[i], &f[i]);
    }
    s = x[l], t = y[l];
    for(int i = 1; i <= m; i++) {
        if(i != l && f[i] <= f[l]) {
            Add(x[i], y[i], f[l] - f[i] + 1);
            Add(y[i], x[i], f[l] - f[i] + 1);
        }
    }
    printf("%d\n", Dinic());
    return 0;
}

P5934 [清华集训2012]最小生成树

这道题目与上一道不同的有两点,

  • 可能出现,可选这条边,可不选这条边,那就要使能到这两个点的所有路径中都有一条的权值 ≥ l \geq l l了。
  • 直接删边,代价改成 1 1 1就好了。
/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 4e5 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, l, dep[N], x[N], y[N], f[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = 0;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head);
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= m; i++) {
        scanf("%d %d %d", &x[i], &y[i], &f[i]);
    }
    scanf("%d %d %d", &s, &t, &l);
    for(int i = 1; i <= m; i++) {
        if(f[i] < l) {
            Add(x[i], y[i], 1);
            Add(y[i], x[i], 1);
        }
    }
    int ans = Dinic();
    memset(head, -1, sizeof head), cnt = 0;
    for(int i = 1; i <= m; i++) {
        if(f[i] > l) {
            Add(x[i], y[i], 1);
            Add(y[i], x[i], 1);
        }
    }
    ans += Dinic();
    printf("%d\n", ans);
    return 0;
}

#6001. 「网络流 24 题」太空飞行计划

最大权闭合子图模板

S S S点连向正权值的点(权值累加),负权值的点连向 T T T,然后在每个关系中建立流量为无穷的有向边。

跑一遍最大流,最大权值为(累加的权值 - 最小割(最大流)), d e p dep dep数组标记为不为 − 1 -1 1的点,即被选中的点。

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, l, ans, dep[N], x[N], y[N], f[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = -1;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head);
    scanf("%d %d", &n, &m);
    s = 0, t = n + m + 1;
    for(int i = 1, x; i <= n; i++) {
        scanf("%d", &x);
        add(s, i, x);
        ans += x;
        while(getchar() == ' ') {
            scanf("%d", &x);
            add(i, n + x, inf);
        }
    }
    for(int i = 1, x; i <= m; i++) {
        scanf("%d", &x);
        add(n + i, t, x);
    }
    ans -= Dinic();
    for(int i = 1, flag = 0; i <= n; i++) {
        if(dep[i] != -1) {
            if(!flag) {
                flag = 1;
            }
            else {
                printf(" ");
            }
            printf("%d", i);
        }
    }
    puts("");
    for(int i = n + 1, flag = 0; i <= n + m; i++) {
        if(dep[i] != -1) {
            if(!flag) {
                flag = 1;
            }
            else {
                printf(" ");
            }
            printf("%d", i - n);
        }
    }
    printf("\n%d\n", ans);
    return 0;
}

Firing

/*
  Author : lifehappy
*/
// #include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

#define int long long

const int N = 1e6 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, dep[N], value[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = -1;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

signed main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    while(scanf("%lld %lld", &n, &m) != EOF) {
        memset(head, -1, sizeof head), cnt = 0;
        s = 0, t = n + 1;
        int ans = 0;
        for(int i = 1; i <= n; i++) {
            int value;
            scanf("%lld", &value);
            if(value > 0) {
                ans += value;
                add(s, i, value);
            }
            else {
                add(i, t, -value);
            }
        }
        for(int i = 1; i <= m; i++) {
            int x, y;
            scanf("%lld %lld", &x, &y);
            add(x, y, inf * inf);
        }
        ans -= Dinic();
        int res = 0;
        for(int i = 1; i <= n; i++) {
            if(dep[i] != -1) {
                res++;
            }
        }
        printf("%lld %lld\n", res, ans);
    }
    return 0;
}

[网络流 24 题]最小路径覆盖

最小路径数为 顶 点 个 数 − 最 大 匹 配 数 顶点个数- 最大匹配数

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, dep[N], x[N], y[N], f[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = -1;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

void print(int rt) {
    printf("%d ", rt);
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(cap[i] || to[i] == s || to[i] == rt + n) continue;
        print(to[i] - n);
        return ;
    }
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head), cnt = 0;
    scanf("%d %d", &n, &m);
    s = 0, t = 2 * n + 1;
    for(int i = 1; i <= n; i++) {
        add(s, i, 1);
        add(i + n, t, 1);
    }
    for(int i = 1; i <= m; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        add(x, y + n, 1);
    }
    int ans = Dinic();
    for(int i = 1; i <= n; i++) {
        int flag = 1;
        for(int j = head[i + n]; ~j; j = nex[j]) {
            if(cap[j] && to[j] != i && to[j] != t) {
                flag = 0;
                break;
            }
        }
        if(flag) {
            print(i);
            puts("");
        }
    }
    printf("%d\n", n - ans);
    return 0;
}

[网络流 24 题 魔术球]

最小路径覆盖的变形题。

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, tot, ans, dep[N], x[N], y[N], f[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);

    while (q.size()) {
        int u = q.front();
        q.pop();

        for (int i = head[u]; ~i; i = nex[i]) {
            if (dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }

    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if (rt == t)
        return flow;

    int res = flow;

    for (int i = head[rt]; ~i; i = nex[i]) {
        if (dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));

            if (temp == 0)
                dep[to[i]] = -1;

            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }

        if (res == 0)
            break;
    }

    return flow - res;
}

int Dinic() {
    int ans = 0;

    while (bfs()) {
        ans += dfs(s, inf);
    }

    return ans;
}

void print(int rt) {
    for (int i = head[rt]; ~i; i = nex[i]) {
        if (cap[i] || to[i] == s || to[i] == rt + m)
            continue;

        printf(" %d", to[i] - m);
        print(to[i] - m);
        return ;
    }
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head), cnt = 0;
    scanf("%d", &n);
    tot = 0, m = 5000, s = 0, t = 10001;

    while (++tot) {
        add(s, tot, 1), add(tot + m, t, 1);

        for (int i = 1; i < tot; i++) {
            if (sqrt(i + tot) == int(sqrt(i + tot))) {
                add(i, tot + m, 1);
            }
        }

        ans += Dinic();

        if (tot - ans > n)
            break;
    }

    printf("%d\n", tot - 1);

    for (int i = 1; i < tot; i++) {
        int flag = 1;

        for (int j = head[i + m]; ~j; j = nex[j]) {
            if (cap[j] && to[j] != i && to[j] != t) {
                flag = 0;
                break;
            }
        }

        if (flag) {
            printf("%d", i);
            print(i);
            puts("");
        }
    }

    return 0;
}

[网络流 24 题]圆桌聚餐

挺好想的这题,直接二分图匹配,然后输出方案数就行了。

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, dep[N], x[N], y[N], f[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = -1;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

void print(int rt) {
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(cap[i] || to[i] == s || to[i] == rt + m) continue;
        printf(" %d", to[i] - m);
        print(to[i] - m);
        return ;
    }
}

vector<int> res[300];

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head), cnt = 0;
    scanf("%d %d", &m, &n);
    s = 0, t = n + m + 1;
    int sum1 = 0;
    for(int i = 1; i <= m; i++) {
        int x;
        scanf("%d", &x);
        add(i + n, t, x);
        sum1 += x;
    }
    int sum2 = 0;
    for(int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        add(s, i, x);
        sum2 += x;
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            add(i, j + n, 1);
        }
    }
    int ans = Dinic();
    if(ans != min(sum1, sum2)) {
        puts("0");
        return 0;
    }
    printf("%d\n", 1);
    for(int i = 1; i <= n; i++) {
        for(int j = head[i]; ~j; j = nex[j]) {
            if(cap[j] == 0 && to[j] != s) {
                res[to[j] - n].push_back(i);
            }
        }
    }
    for(int i = 1; i <= m; i++) {
        for(auto it : res[i]) {
            printf("%d ", it);
        }
        puts("");
    }
    return 0;
}

[网络流 24 题]试题库

有点像二分图最大匹配,其实好像就是吧。

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, dep[N], x[N], y[N], f[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = -1;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

void print(int rt) {
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(cap[i] || to[i] == s || to[i] == rt + m) continue;
        printf(" %d", to[i] - m);
        print(to[i] - m);
        return ;
    }
}

vector<int> res[50];

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head), cnt = 0;
    scanf("%d %d", &m, &n);
    s = 0, t = n + m + 1;
    int sum = 0;
    for(int i = 1; i <= m; i++) {
        int x;
        scanf("%d", &x);
        add(n + i, t, x);
        sum += x;
    }
    for(int i = 1; i <= n; i++) {
        int tot, x;
        scanf("%d", &tot);
        add(s, i, 1);
        for(int j = 1; j <= tot; j++) {
            scanf("%d", &x);
            add(i, x + n, 1);
        }
    }
    int ans = Dinic();
    if(ans != sum) {
        puts("No Solution!");
        return 0;
    }
    for(int i = 1; i <= n; i++) {
        for(int j = head[i]; ~j; j = nex[j]) {
            if(!cap[j] && to[j] != s) {
                res[to[j] - n].push_back(i);
            }
        }
    }
    for(int i = 1; i <= m; i++) {
        printf("%d: ", i);
        for(auto it : res[i]) {
            printf("%d ", it);
        }
        puts("");
    }
    return 0;
}

[网络流 24 题]最长递增子序列

先跑一次 d p dp dp求得 s s s

对于问题二,先拆点然后对所有 d p [ i ] = 1 dp[i] = 1 dp[i]=1的连一条 a d d ( s , i , 1 ) add(s, i, 1) add(s,i,1)的边,对所有 d p [ i ] = s dp[i] = s dp[i]=s的点连一条 a d d ( i + n , t , 1 ) add(i + n, t, 1) add(i+n,t,1)的边

然后对 i < j , a [ i ] ≤ a [ j ] , d p [ i ] + 1 = d p [ j ] i < j, a[i] \leq a[j],dp[i] + 1 = dp[j] i<j,a[i]a[j],dp[i]+1=dp[j],连一条 a d d ( i + n , j , 1 ) add(i + n, j, 1) add(i+n,j,1)的边,然后跑一遍最大流即可了。

对于问题二, a d d ( s , 1 , i n f ) , a d d ( 1 , n + 1 , i n f ) add(s, 1, inf), add(1, n + 1, inf) add(s,1,inf),add(1,n+1,inf),如果 d p [ n ] = s dp[n] = s dp[n]=s a d d ( n , n + n , i n f ) , a d d ( n + n , T , i n f ) add(n, n + n, inf), add(n + n, T, inf) add(n,n+n,inf),add(n+n,T,inf)然后跑一遍最大流即可。

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, res, dep[N], x[N], y[N], f[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = -1;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

void print(int rt) {
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(cap[i] || to[i] == s || to[i] == rt + m) continue;
        printf(" %d", to[i] - m);
        print(to[i] - m);
        return ;
    }
}

const int N1 = 510;

int a[N], dp[N];

void solve1() {
    for(int i = 1; i <= n; i++) {
        dp[i] = 1;
        for(int j = 1; j < i; j++) {
            if(a[i] >= a[j]) {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        res = max(res, dp[i]);
    }
    printf("%d\n", res);
}

int solve2() {
    memset(head, -1, sizeof head), cnt = 0, s = 0, t = 2 * n + 1;
    for(int i = 1; i <= n; i++) {
        if(dp[i] == 1) {
            add(s, i, 1);
        }
        if(dp[i] == res) {
            add(i + n, t, 1);
        }
        add(i, i + n, 1);
        for(int j = i + 1; j <= n; j++) {
            if(a[j] >= a[i] && dp[i] + 1 == dp[j]) {
                add(i + n, j, 1);
            }
        }
    }
    int ans = Dinic();
    printf("%d\n", ans);
    return ans;
}

void solve3() {
    int ans = solve2();
    add(s, 1, inf), add(1, 1 + n, inf);
    if(dp[n] == res) {
        add(n, n + n, inf);
        add(n + n, t, inf);
    }
    printf("%d\n", Dinic() + ans);
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    if(n == 1) {
        puts("1\n1\n1");
        return 0;
    }
    solve1();
    solve3();
    return 0;
}

[网络流 24 题]方格取数

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10, inf = 0x3f3f3f3f;

int head[N], to[N], nex[N], cap[N], cnt;

int s, t, n, m, dep[N], x[N], y[N], f[N];

void Add(int x, int y, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int c) {
    Add(x, y, c);
    Add(y, x, 0);
}

bool bfs() {
    queue<int> q;
    memset(dep, -1, sizeof dep);
    dep[s] = 0;
    q.push(s);
    while(q.size()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = nex[i]) {
            if(dep[to[i]] == -1 && cap[i]) {
                q.push(to[i]);
                dep[to[i]] = dep[u] + 1;
            }
        }
    }
    return dep[t] != -1;
}

int dfs(int rt, int flow) {
    if(rt == t) return flow;
    int res = flow;
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(dep[to[i]] == dep[rt] + 1 && cap[i]) {
            int temp = dfs(to[i], min(res, cap[i]));
            if(temp == 0) dep[to[i]] = -1;
            res -= temp;
            cap[i] -= temp;
            cap[i ^ 1] += temp;
        }
        if(res == 0) break;
    }
    return flow - res;
}

int Dinic() {
    int ans = 0;
    while(bfs()) {
        ans += dfs(s, inf);
    }
    return ans;
}

void print(int rt) {
    for(int i = head[rt]; ~i; i = nex[i]) {
        if(cap[i] || to[i] == s || to[i] == rt + m) continue;
        printf(" %d", to[i] - m);
        print(to[i] - m);
        return ;
    }
}

const int ax[4] = {1, -1, 0, 0}, ay[4] = {0, 0, 1, -1};

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head), cnt = 0;
    scanf("%d %d", &n, &m);
    s = 0, t = n * m + 1;
    int sum = 0;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            int x;
            scanf("%d", &x);
            sum += x;
            if((i + j) & 1) {
                add(s, (i - 1) * m + j, x);
                for(int k = 0; k < 4; k++) {
                    int x = i + ax[k], y = j + ay[k];
                    if(x < 1 || x > n || y < 1 || y > m) continue;
                    add((i - 1) * m + j, (x - 1) * m + y, inf);
                }
            }
            else {
                add((i - 1) * m + j, t, x);
            }
        }
    }
    printf("%d\n", sum - Dinic());
    return 0;
}

[网络流 24 题]餐巾计划

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef pair<ll, ll> pii;

const int N = 5e5 + 10;
ll inf = 0x3f3f3f3f3f3f3f3f;

ll head[N], cap[N], to[N], nex[N], value[N], cnt;

ll n, m, s, t, dis[N], vis[N], flow[N], pre[N];

void Add(int x, int y, int w, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    value[cnt] = w;
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int w, int c) {
    Add(x, y, w, c);
    Add(y, x, -w, 0);
}

bool spfa() {
    queue<int> q;
    memset(dis, 0x3f, sizeof dis);
    memset(vis, 0, sizeof vis);
    q.push(s), dis[s] = 0, vis[s] = 1;
    flow[s] = 1 << 30;
    while(q.size()) {
        int rt = q.front();
        q.pop(), vis[rt] = 0;
        for(int i = head[rt]; ~i; i = nex[i]) {
            if(cap[i] && dis[to[i]] > dis[rt] + value[i]) {
                dis[to[i]] = dis[rt] + value[i];
                flow[to[i]] = min(flow[rt], cap[i]);
                pre[to[i]] = i;
                if(!vis[to[i]]) {
                    vis[to[i]] = 1;
                    q.push(to[i]);
                }
            }
        }
    }
    return dis[t] != 0x3f3f3f3f3f3f3f3f;
}

pii Mcmf() {
    ll res = 0, ans = 0;
    while(spfa()) {
        int cur = flow[t];
        res += cur, ans += dis[t] * cur;
        int now = t;
        while(now != s) {
            cap[pre[now]] -= cur;
            cap[pre[now] ^ 1] += cur;
            now = to[pre[now] ^ 1];
        }
    }
    return make_pair(res, ans);
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head), cnt = 0;
    int P, M, F, N, S;
    scanf("%d", &n);
    s = 0, t = 2 * n + 1;
    for(int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        add(s, i, 0, x);
        add(i + n, t, 0, x);
    }
    scanf("%d %d %d %d %d", &P, &M, &F, &N, &S);
    for(int i = 1; i <= n; i++) {
        add(s, i + n, P, inf);
        if(i + 1 <= n) add(i, i + 1, 0, inf);
        if(i + M <= n) add(i, i + M + n, F, inf);
        if(i + N <= n) add(i, i + N + n, S, inf);
    }
    pii ans = Mcmf();
    // printf("%d\n", ans.second);
    cout << ans.second << "\n";
    return 0;
}

[网络流 24 题]数字梯形

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef pair<int, int> pii;

const int N = 5e5 + 10, inf = 0x3f3f3f3f;

int head[N], cap[N], to[N], nex[N], value[N], cnt;

int n, m, s, t, dis[N], vis[N], flow[N], pre[N];

void Add(int x, int y, int w, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    value[cnt] = w;
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int w, int c) {
    Add(x, y, w, c);
    Add(y, x, -w, 0);
}

bool spfa() {
    queue<int> q;
    memset(dis, 0x3f, sizeof dis);
    memset(vis, 0, sizeof vis);
    q.push(s), dis[s] = 0, vis[s] = 1;
    flow[s] = 1 << 30;
    while(q.size()) {
        int rt = q.front();
        q.pop(), vis[rt] = 0;
        for(int i = head[rt]; ~i; i = nex[i]) {
            if(cap[i] && dis[to[i]] > dis[rt] + value[i]) {
                dis[to[i]] = dis[rt] + value[i];
                flow[to[i]] = min(flow[rt], cap[i]);
                pre[to[i]] = i;
                if(!vis[to[i]]) {
                    vis[to[i]] = 1;
                    q.push(to[i]);
                }
            }
        }
    }
    return dis[t] != 0x3f3f3f3f;
}

pii Mcmf() {
    int res = 0, ans = 0;
    while(spfa()) {
        int cur = flow[t];
        res += cur, ans += dis[t] * cur;
        int now = t;
        while(now != s) {
            cap[pre[now]] -= cur;
            cap[pre[now] ^ 1] += cur;
            now = to[pre[now] ^ 1];
        }
    }
    return make_pair(res, ans);
}

int a[50][50], id[50][50], tot;

void solve1() {
    memset(head, -1, sizeof head), cnt = 0;
    s = 0, t = 2 * tot + 1;
    for(int i = 1; i <= n; i++) {
        add(s, id[1][i], 0, 1);
    }
    for(int i = 1; i < m; i++) {
        for(int j = 1; j <= n + i - 1; j++) {
            add(id[i][j], id[i][j] + tot, -a[i][j], 1);
            add(id[i][j] + tot, id[i + 1][j], 0, 1);
            add(id[i][j] + tot, id[i + 1][j + 1], 0, 1);
        }
    }
    for(int i = 1; i <= n + m - 1; i++) {
        add(id[m][i], id[m][i] + tot, -a[m][i], 1);
        add(id[m][i] + tot, t, 0, 1);
    }
    printf("%d\n", -Mcmf().second);
}

void solve2() {
    memset(head, -1, sizeof head), cnt = 0;
    s = 0, t = 2 * tot + 1;
    for(int i = 1; i <= n; i++) {
        add(s, id[1][i], 0, 1);
    }
    for(int i = 1; i < m; i++) {
        for(int j = 1; j <= n + i - 1; j++) {
            add(id[i][j], id[i][j] + tot, -a[i][j], inf);
            add(id[i][j] + tot, id[i + 1][j], 0, 1);
            add(id[i][j] + tot, id[i + 1][j + 1], 0, 1);
        }
    }
    for(int i = 1; i <= n + m - 1; i++) {
        add(id[m][i], id[m][i] + tot, -a[m][i], inf);
        add(id[m][i] + tot, t, 0, inf);
    }
    printf("%d\n", -Mcmf().second);
}

void solve3() {
    memset(head, -1, sizeof head), cnt = 0;
    s = 0, t = 2 * tot + 1;
    for(int i = 1; i <= n; i++) {
        add(s, id[1][i], 0, 1);
    }
    for(int i = 1; i < m; i++) {
        for(int j = 1; j <= n + i - 1; j++) {
            add(id[i][j], id[i][j] + tot, -a[i][j], inf);
            add(id[i][j] + tot, id[i + 1][j], 0, inf);
            add(id[i][j] + tot, id[i + 1][j + 1], 0, inf);
        }
    }
    for(int i = 1; i <= n + m - 1; i++) {
        add(id[m][i], id[m][i] + tot, -a[m][i], inf);
        add(id[m][i] + tot, t, 0, inf);
    }
    printf("%d\n", -Mcmf().second);
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= m; i++) {
        for(int j = 1; j <= n + i - 1; j++) {
            scanf("%d", &a[i][j]);
            id[i][j] = ++tot;
        }
    }
    solve1();
    solve2();
    solve3();
    return 0;
}

[网络流 24 题]运输问题

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef pair<int, int> pii;

const int N = 5e5 + 10, inf = 0x3f3f3f3f;

int head[N], cap[N], to[N], nex[N], value[N], cnt;

int n, m, s, t, dis[N], vis[N], flow[N], pre[N];

void Add(int x, int y, int w, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    value[cnt] = w;
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int w, int c) {
    Add(x, y, w, c);
    Add(y, x, -w, 0);
}

bool spfa() {
    queue<int> q;
    memset(dis, 0x3f, sizeof dis);
    memset(vis, 0, sizeof vis);
    q.push(s), dis[s] = 0, vis[s] = 1;
    flow[s] = 1 << 30;
    while(q.size()) {
        int rt = q.front();
        q.pop(), vis[rt] = 0;
        for(int i = head[rt]; ~i; i = nex[i]) {
            if(cap[i] && dis[to[i]] > dis[rt] + value[i]) {
                dis[to[i]] = dis[rt] + value[i];
                flow[to[i]] = min(flow[rt], cap[i]);
                pre[to[i]] = i;
                if(!vis[to[i]]) {
                    vis[to[i]] = 1;
                    q.push(to[i]);
                }
            }
        }
    }
    return dis[t] != 0x3f3f3f3f;
}

pii Mcmf() {
    int res = 0, ans = 0;
    while(spfa()) {
        int cur = flow[t];
        res += cur, ans += dis[t] * cur;
        int now = t;
        while(now != s) {
            cap[pre[now]] -= cur;
            cap[pre[now] ^ 1] += cur;
            now = to[pre[now] ^ 1];
        }
    }
    return make_pair(res, ans);
}

const int N1 = 110;

int a[N1], b[N1], x[N1][N1];

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    memset(head, -1, sizeof head), cnt = 0;
    scanf("%d %d", &n, &m);
    s = 0, t = n + m + 1;
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        add(s, i, 0, a[i]);
    }
    for(int i = 1; i <= m; i++) {
        scanf("%d", &b[i]);
        add(i + n, t, 0, b[i]);
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            scanf("%d", &x[i][j]);
            add(i, j + n, x[i][j], inf);
        }
    }
    printf("%d\n", Mcmf().second);
    memset(head, -1, sizeof head), cnt = 0;
    for(int i = 1; i <= n; i++) {
        add(s, i, 0, a[i]);
    }
    for(int i = 1; i <= m; i++) {
        add(i + n, t, 0, b[i]);
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            add(i, j + n, -x[i][j], inf);
        }
    }
    printf("%d\n", -Mcmf().second);
    return 0;
}

[网络流 24 题]分配问题

/*
  Author : lifehappy
*/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef pair<int, int> pii;

const int N = 5e5 + 10, inf = 0x3f3f3f3f;

int head[N], cap[N], to[N], nex[N], value[N], cnt;

int n, m, s, t, dis[N], vis[N], flow[N], pre[N];

void Add(int x, int y, int w, int c) {
    to[cnt] = y;
    nex[cnt] = head[x];
    value[cnt] = w;
    cap[cnt] = c;
    head[x] = cnt++;
}

void add(int x, int y, int w, int c) {
    Add(x, y, w, c);
    Add(y, x, -w, 0);
}

bool spfa() {
    queue<int> q;
    memset(dis, 0x3f, sizeof dis);
    memset(vis, 0, sizeof vis);
    q.push(s), dis[s] = 0, vis[s] = 1;
    flow[s] = 1 << 30;
    while(q.size()) {
        int rt = q.front();
        q.pop(), vis[rt] = 0;
        for(int i = head[rt]; ~i; i = nex[i]) {
            if(cap[i] && dis[to[i]] > dis[rt] + value[i]) {
                dis[to[i]] = dis[rt] + value[i];
                flow[to[i]] = min(flow[rt], cap[i]);
                pre[to[i]] = i;
                if(!vis[to[i]]) {
                    vis[to[i]] = 1;
                    q.push(to[i]);
                }
            }
        }
    }
    return dis[t] != 0x3f3f3f3f;
}

pii Mcmf() {
    int res = 0, ans = 0;
    while(spfa()) {
        int cur = flow[t];
        res += cur, ans += dis[t] * cur;
        int now = t;
        while(now != s) {
            cap[pre[now]] -= cur;
            cap[pre[now] ^ 1] += cur;
            now = to[pre[now] ^ 1];
        }
    }
    return make_pair(res, ans);
}

const int N1 = 110;

int x[N1][N1];

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            scanf("%d", &x[i][j]);       
        }
    }
    s = 0, t = n + n + 1;
    memset(head, -1, sizeof head), cnt = 0;
    for(int i = 1; i <= n; i++) {
        add(s, i, 0, 1);
    }
    for(int i = 1; i <= n; i++) {
        add(i + n, t, 0, 1);
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            add(i, j + n, x[i][j], 1);
        }
    }
    printf("%d\n", Mcmf().second);
    memset(head, -1, sizeof head), cnt = 0;
    for(int i = 1; i <= n; i++) {
        add(s, i, 0, 1);
    }
    for(int i = 1; i <= n; i++) {
        add(i + n, t, 0, 1);
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            add(i, j + n, -x[i][j], 1);
        }
    }
    printf("%d\n", -Mcmf().second);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值