Minimum-cost Flow

链接:https://ac.nowcoder.com/acm/contest/5666/H
来源:牛客网

题目描述
Bobo has a network of n n n nodes and m m m arcs. The i i i-th arc goes from the a i a_i ai-th node to the b i b_i bi-th node, with cost c i c_i ci.

Bobo also asks q q q questions. The i i i-th question is specified by two integers u i u_i ui and v i v_i vi, which is to ask the minimum cost to send one unit of flow from the 1 1 1-th node to the n n n-th node, when all the edges have capacity u i v i \frac{u_i}{v_i} viui (a fraction).

You can refer the wiki page for further information of Minimum-cost Flow.

输入描述:
The input consists of several test cases terminated by end-of-file.

The first line of each test case contains two integers n n n and m m m. The i i i-th of the following m m m lines contains three integers a i a_i ai, b i b_i bi and c i c_i ci. The next line contains an integer q q q. The i i i-th of the last q q q lines contains two integers u i u_i ui and v i v_i vi.

  • 2 ≤ n ≤ 50 2 \leq n \leq 50 2n50
  • 1 ≤ m ≤ 100 1 \leq m \leq 100 1m100
  • 1 ≤ a i , b i ≤ n 1 \leq a_i, b_i \leq n 1ai,bin
  • 1 ≤ c i ≤ 1 0 5 1 \leq c_i \leq 10^5 1ci105
  • 1 ≤ q ≤ 1 0 5 1 \leq q \leq 10^5 1q105
  • 0 ≤ u i ≤ v i ≤ 1 0 9 0 \leq u_i \leq v_i \leq 10^9 0uivi109
  • The sum of m does not exceed 1 0 4 10^4 104.
  • The sum of q does not exceed 1 0 6 10^6 106.

输出描述:
For each test case, print q q q fractions (or NaN, if it is impossible to send one unit of flow) which denote the answer.
示例1

输入
2 1
1 2 2
1
1 1
2 2
1 2 1
1 2 2
3
1 2
2 3
1 4
输出
2/1
3/2
4/3
NaN

假设每条边容量为 u v \frac{u}{v} vu,流量为 1 1 1的最小费用为 w ⋅ u v \frac{w·u}{v} vwu,则每条边容量为 1 1 1,流量为 v u \frac{v}{u} uv的最小费用为 w w w
因此首先设每条边容量为 1 1 1跑费用流,记录第 i i i条增广路经的费用增量为 p a t h [ i ] path[i] path[i],并求前缀和 s [ i ] s[i] s[i]
由于边数为1,每次求得的增广路流量为1,且spfa每次求得的是当前最小花费的增广路,因此 s [ i ] s[i] s[i]表示流量为 i i i时的最小费用。
如果流量 v u \frac{v}{u} uv大于最大流则不存在,否则最小费用为 w = s [ ⌊ v u ⌋ ] + p a t h [ ⌊ v u ⌋ + 1 ] ⋅ ( v u − ⌊ v u ⌋ ) w=s[\lfloor \frac{v}{u}\rfloor ]+path[\lfloor \frac{v}{u}\rfloor+1]·(\frac{v}{u}-\lfloor \frac{v}{u}\rfloor) w=s[uv]+path[uv+1](uvuv)
由此可以得出每条边容量为 u v \frac{u}{v} vu,流量为 1 1 1的最小费用为 w ⋅ u v = s [ ⌊ v u ⌋ ] ⋅ u + p a t h [ ⌊ v u ⌋ + 1 ] ⋅ ( v m o d    u ) v \frac{w·u}{v}=\frac{s[\lfloor \frac{v}{u}\rfloor ]·u+path[\lfloor \frac{v}{u}\rfloor+1]·(v\mod u)}{v} vwu=vs[uv]u+path[uv+1](vmodu),然后分数化简即可得到答案。

#include

#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector
#define pii pair
#define mii unordered_map
#define msi unordered_map
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define INF LONG_LONG_MAX
#define pr(x) cout<<#x<<": "<
using namespace std;

inline int qr() {
    int f = 0, fu = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')fu = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        f = (f << 3) + (f << 1) + c - 48;
        c = getchar();
    }
    return f * fu;
}

const int N = 55, M = 1005;
ll path[M], s[M];
int tt;
namespace EK {
    int s, t, head[N], ver[M], Next[M], tot = 1, pre[N];
    bool v[N];
    int n, edge[M], c[M];
    ll d[N];

    inline void add(int x, int y, int z, int w) {
        ver[++tot] = y, Next[tot] = head[x], edge[tot] = z, c[tot] = w, head[x] = tot;
        ver[++tot] = x, Next[tot] = head[y], edge[tot] = 0, c[tot] = -w, head[y] = tot;
    }

    inline bool spfa() {
        repi(i, 1, n)v[i] = false, d[i] = INF;
        deque<int> q;
        q.push_back(s), v[s] = true, d[s] = 0;
        while (!q.empty()) {
            int x = q.front();
            q.pop_front(), v[x] = false;
            for (register int i = head[x]; i; i = Next[i]) {
                int y = ver[i], z = edge[i];
                int w = c[i];
                if (!z || d[y] <= d[x] + w) continue;
                d[y] = d[x] + w, pre[y] = i;
                if (!v[y]) {
                    (q.empty() || d[y] > d[q.front()]) ? q.push_back(y) : q.push_front(y);
                    v[y] = true;
                }
            }
        }
        return d[t] != INF;
    }

    inline void upd() {
        path[++tt] = d[t];
        int x = t;
        while (x != s)
            edge[pre[x]]--, edge[pre[x] ^ 1]++, x = ver[pre[x] ^ 1];
    }

    inline void solve() {
        while (spfa())upd();
    }

    inline void init(int _n, int _s, int _t) {
        tot = 1, n = _n, s = _s, t = _t;
        repi(i, 1, n)head[i] = 0;
    }
}
int n, m, q;

int main() {
    while (scanf("%d%d", &n, &m) != EOF) {
        EK::init(n, 1, n), tt = 0;
        while (m--) {
            int x = qr(), y = qr(), w = qr();
            EK::add(x, y, 1, w);
        }
        EK::solve();
        q = qr();
        repi(i, 1, tt)s[i] = s[i - 1] + path[i];
        while (q--) {
            int u = qr(), v = qr();
            if (1ll * tt * u < v) {
                puts("NaN");
                continue;
            }
            ll x = s[v / u] * u + path[v / u + 1] * (v % u);
            ll gcd = __gcd(x, 1ll * v);
            printf("%lld/%lld\n", x / gcd, v / gcd);
        }
    }
    return 0;
}

你可能感兴趣的:(费用流,ACM)