H - Minimum-cost Flow

H 有趣的网络流

题意


费用网络中每条边的容量均为u/v,输入大小为1的流,问最小费用是多少。多次询问不同的u/v。

思路


先特判容量为0,输出NaN。

考虑转化网络,容量为u/v的边可以看作容量为1(F)的边(F为单位),那么输入大小为1的流相当于输入大小为 v/u (F) 的流
由于费用流容量均为一,EK费用流中,每次迭代增加的最大流量均为1,记录每次迭代中,当前流量与最小费用的关系,可得到流量与最小费用的数组ans

如果边的容量为u/v 输入流的大小为 v/u(F):
1、若v/u > maxflow,输出NaN,反之执行2
2、若v/u 为整数,直接输出ans[v/u] * u/v (单位转换),反之执行3
3、若v/u 不为整数,进行插值,并进行单位转化,输出结果

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <map>

using namespace std;
using ll = long long;

const int N = 55, M = 205;

struct edge {
    int to, w, cost;
} edges[M];

vector<int> out_edges[N];
int vis[N], d[N], flow[N], fa[N], last[N];
int tot;

ll ans[M];

inline void init() {
    tot = 0;
    for (int i = 0; i < N; ++i) 
        out_edges[i].clear(); 
}

inline void add_edge(int u, int v, int w, int cost) {
    edges[tot] = {v, w, cost};
    out_edges[u].emplace_back(tot++);
}


bool spfa(int s, int t) {
    memset(vis, 0, sizeof(vis));
    memset(flow, 0x3f, sizeof(flow));
    memset(d, 0x3f, sizeof(d));
    queue<int> que;
    que.push(s), vis[s] = 1, d[s] = 0, fa[t] = -1;
    while (!que.empty()) {
        int u = que.front();
        que.pop();
        vis[u] = 0;
        for (int i : out_edges[u]) {
            int v = edges[i].to;
            if(edges[i].w > 0 && d[v] > d[u] + edges[i].cost){
                d[v] = d[u] + edges[i].cost;
                fa[v] = u;
                last[v] = i;
                flow[v] = std::min(flow[u], edges[i].w);
                if(!vis[v]){
                    vis[v] = 1;
                    que.push(v);
                }
            }
        }
    }
    return fa[t] != -1;
}


void mcmf(int s, int t, ll &maxflow, ll &mincost) {
    maxflow = 0, mincost = 0;
    while (spfa(s, t)) {
        int u = t;
        maxflow += flow[t];
        mincost += flow[t] * d[t];
        ans[maxflow] = mincost;
        while(u != s){
            edges[last[u]].w -= flow[t];
            edges[last[u] ^ 1].w += flow[t];
            u = fa[u];
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n, m;
    while(cin >> n >> m){
        init();
        for (int i = 0; i < m; ++i) {
            int u, v, cost;
            cin >> u >> v >> cost;
            add_edge(u, v, 1, cost);
            add_edge(v, u, 0, -cost);
        }
        ll maxflow, mincost;
        mcmf(1, n, maxflow, mincost);
        ans[0] = 0;
        ans[maxflow + 1] = ans[maxflow];

        int q;
        cin >> q;
        while(q--) {
            ll x, y;
            cin >> x >> y;

            if (x == 0 || y > x * maxflow) {
                cout << "NaN\n";
                continue;
            }

            ll p = y / x;

            ll up = ans[p] * x + (y % x) * (ans[p + 1] - ans[p]);
            ll low = y;

            ll temp = __gcd(up, low);
            cout << up / temp << "/" << low / temp << "\n";
        }
    }
    return 0;
}
全部评论

相关推荐

点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务