链接: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.
输出描述:
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} vw⋅u,则每条边容量为 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]⋅(uv−⌊uv⌋)。
由此可以得出每条边容量为 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} vw⋅u=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;
}