P4012 深海机器人问题(网络流24题-智慧限制边+最大费用最大流)

传送门

同一条边可以经过多次,但仅有第一次经过时能够获得价值,可以建图:存在一条流量为 1 1 1 价值为 w w w 的边和一条流量为 i n f inf inf 价值为 0 0 0 的边。

建边方式比较变态,最后的 a a a 个出发点和 b b b 个终止点套用超级源点和超级汇点即可。


参考代码

#include <bits/stdc++.h>
#define itn int
#define int long long
#define endl "\n"
#define PII pair<int, int>
using namespace std;
const int N = 1e5 + 10;
const int M = 5e4 + 10;
const itn inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
//const int mod = 998244353;

template <int N>
struct MCMF {
    struct E {
        int to, cap, val, inv;
    };
    vector<E> g[N];
    int dis[N], now[N], h[N], pre[N], preu[N];
    void add(int u, int v, int f, int w) {
        g[u].push_back({v, f, w, (int)g[v].size()});
        g[v].push_back({u, 0, -w, (int)g[u].size() - 1});
    }
    void dijkstra(int st) {
        priority_queue<pair<int, int>, vector<pair<int, int>>,
                       greater<pair<int, int>>>
            q;
        memset(dis, 0x3f, sizeof dis);
        memset(pre, -1, sizeof pre);
        memset(preu, -1, sizeof preu);
        dis[st] = 0;
        q.push({0, st});
        while (q.size()) {
            // auto [d, u] = q.top();
            auto qnow = q.top();
            int d = qnow.first, u = qnow.second;
            q.pop();
            if (dis[u] < d)
                continue;
            int x = 0;
            for (auto gnow : g[u]) {
                int v = gnow.to, f = gnow.cap, w = gnow.val, inv = gnow.inv;
                if (f && dis[v] > dis[u] + w + h[u] - h[v]) {
                    dis[v] = dis[u] + h[u] - h[v] + w;
                    pre[v] = x;
                    preu[v] = u;
                    q.push({dis[v], v});
                }
                x++;
            }
        }
    }
    pair<int, int> min_cost_max_flow(int st, int ed) {
        memset(h, 0, sizeof h);
        for (int flow = 0, cost = 0, res = inf;; res = inf) {
            dijkstra(st);
            if (dis[ed] > inf)
                return {flow, cost};
            for (int i = 0; i < N; i++) {
                h[i] += dis[i];
            }
            for (int i = ed; i != st; i = preu[i]) {
                res = min(res, g[preu[i]][pre[i]].cap);
            }
            flow += res;
            cost += res * h[ed];
            for (int i = ed; i != st; i = preu[i]) {
                g[i][g[preu[i]][pre[i]].inv].cap += res;
                g[preu[i]][pre[i]].cap -= res;
            }
        }
    }
};
MCMF<300> mcmf;
int id[20][20];
int n, k, s, t;
void solve() {
    int a, b, p, q;
    cin >> a >> b >> p >> q;
    s = 0, t = 280;
    int cnt = 0, x;
    for (int i = 0; i <= p; i++) {
        for (int j = 0; j <= q; j++) {
            id[i][j] = ++cnt;
        }
    }
    for (int i = 0; i <= p; i++) {
        for (int j = 0; j < q; j++) {
            cin >> x;
            // cout << id[i][j] << " " << id[i][j+1] << endl;
            mcmf.add(id[i][j], id[i][j + 1], 1, -x);
            mcmf.add(id[i][j], id[i][j + 1], inf, 0);
        }
    }
    for (int j = 0; j <= q; j++) {
        for (int i = 0; i < p; i++) {
            cin >> x;
            // cout << id[i][j - 1] << " " << id[i][j] << endl;
            mcmf.add(id[i][j], id[i + 1][j], 1, -x);
            mcmf.add(id[i][j], id[i + 1][j], inf, 0);
        }
    }
    for (int i = 1; i <= a; i++) {
        int u, v;
        cin >> x >> u >> v;
        // cout << id[u][v] << endl;
        mcmf.add(s, id[u][v], x, 0);
    }
    for (int i = 1; i <= b; i++) {
        int u, v;
        cin >> x >> u >> v;
        // cout << id[u][v] << endl;
        mcmf.add(id[u][v], t, x, 0);
    }

    cout << -mcmf.min_cost_max_flow(s, t).second << endl;
}

signed main() {
    ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cout << fixed << setprecision(12);
    // init();
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值