n n n个点, m m m条边的图,边有费用。
q q q次询问:若每条边的容量为 u v \displaystyle\frac uv vu,则从 1 1 1到 n n n流 1 1 1个单位的流量的最小费用是多少,要求输出最简分数。
n ≤ 50 , m ≤ 100 , q ≤ 1 0 5 , 0 ≤ u ≤ v ≤ 1 0 9 n\le50,m\le100,q\le10^5,0\le u\le v\le10^9 n≤50,m≤100,q≤105,0≤u≤v≤109
首先设 c o s t ( x , y ) {\rm cost}(x,y) cost(x,y)表示每条边容量为 y y y,要从 1 1 1向 n n n流 x x x的流量的费用。则有 c o s t ( x , y ) = y c o s t ( x y , 1 ) \displaystyle{\rm cost}(x,y)=y{\rm cost}(\frac xy,1) cost(x,y)=ycost(yx,1)。
根据费用流的算法流程: c o s t ( n y + y , y ) − c o s t ( n y , y ) {\rm cost}(ny+y,y)-{\rm cost}(ny,y) cost(ny+y,y)−cost(ny,y)表示每条边容量为 y y y时,第 n + 1 n+1 n+1条增广路的费用(流量为y)。若只需要 z z z的流量,则乘上比例系数 z y \displaystyle\frac zy yz即可。
对于 c o s t ( 1 , p ) {\rm cost}(1,p) cost(1,p),设 k = ⌊ 1 p ⌋ \displaystyle k=\lfloor\frac1p\rfloor k=⌊p1⌋。考虑对前 k k k条增广路每条路流 p p p的流量,费用为 c o s t ( k p , p ) = p c o s t ( k , 1 ) {\rm cost}(kp,p)=p{\rm cost}(k,1) cost(kp,p)=pcost(k,1);对第 k + 1 k+1 k+1条增广路流 1 − k p 1-kp 1−kp的流量,费用为 1 − k p p [ c o s t ( k p + p , p ) − c o s t ( k p , p ) ] = ( 1 − k p ) [ c o s t ( k + 1 , 1 ) − c o s t ( k , 1 ) ] \displaystyle\frac{1-kp}{p}[{\rm cost}(kp+p,p)-{\rm cost}(kp,p)]=(1-kp)[{\rm cost}(k+1,1)-{\rm cost}(k,1)] p1−kp[cost(kp+p,p)−cost(kp,p)]=(1−kp)[cost(k+1,1)−cost(k,1)]。
设 f k = c o s t ( k , 1 ) f_k={\rm cost}(k,1) fk=cost(k,1),则有
c o s t ( 1 , p ) = p f k + ( 1 − p k ) ( f k + 1 − f k ) {\rm cost}(1,p)=pf_k+(1-pk)(f_{k+1}-f_k) cost(1,p)=pfk+(1−pk)(fk+1−fk)
综上,设所有边容量为 1 1 1,做一次最小费用最大流求出所有的 f k f_k fk。对于一次询问 p = u v \displaystyle p=\frac uv p=vu,则答案为 u f k + ( v − k u ) ( f k + 1 − f k ) v \displaystyle\frac{uf_k+(v-ku)(f_{k+1}-f_k)}{v} vufk+(v−ku)(fk+1−fk),化成最简分数即可。
单组数据时间复杂度 O ( n 2 m + q log V ) O(n^2m+q\log V) O(n2m+qlogV)
#include
using namespace std;
const int N = 50 + 5, M = 2 * 1000 + 5;
const long long Inf = 1e17;
using ll = long long;
using arr = int[N];
/*-----------------------------------------------------------------*/
int n, m, q, Ecnt, Fi[N];
ll dis[N], f[N];
struct Edge {
int nx, v, c, w;
} E[M];
inline void Add(int u, int v, int c, int w) {
E[++Ecnt] = (Edge){Fi[u], v, c, w}, Fi[u] = Ecnt;
}
class MCMF {
private:
static const int N = 2e5 + 5;
ll h[N];
int Flow[N], Pre[N], From[N];
struct Seg {
int Cnt, tr[N << 2];
inline void Cls() {
fill(tr, tr + 2 * Cnt + 1, 0);
Cnt = 0;
}
inline int Cmp(int a, int b) { return dis[a] < dis[b] ? a : b; }
inline void Set(int n) {
for (Cnt = 1; Cnt < n + 2; Cnt <<= 1)
;
tr[0] = n + 1;
}
inline void Mdy(int u, ll w) {
for (int i = u + Cnt; dis[tr[i]] > w; tr[i] = u, i >>= 1)
;
dis[u] = w;
}
inline void Del(int u) {
for (tr[u += Cnt] = 0, u >>= 1; u;
tr[u] = Cmp(tr[u << 1], tr[u << 1 | 1]), u >>= 1)
;
}
} zkw;
inline bool Dij(int n, int S, int T) {
for (int i = 0; i <= n; ++i)
dis[i] = Inf, Flow[i] = From[i] = Pre[i] = 0;
Flow[S] = 1e9;
dis[n + 1] = 0;
zkw.Cls(), zkw.Set(n);
zkw.Mdy(S, 0);
for (int _ = 2; _ <= n; ++_) {
int u = zkw.tr[1];
zkw.Del(u);
for (int i = Fi[u], v = E[i].v; i; v = E[i = E[i].nx].v)
if (E[i].c > 0 && dis[v] > dis[u] + E[i].w + h[u] - h[v]) {
zkw.Mdy(v, dis[u] + E[i].w + h[u] - h[v]);
From[v] = u, Pre[v] = i;
Flow[v] = min(Flow[u], E[i].c);
}
}
return dis[T] != Inf;
}
public:
int MF;
inline void Calc(int n, int S, int T) {
int Now;
for (int i = 1; i <= n; ++i)
h[i] = 0;
while (Dij(n, S, T)) {
MF += (Now = Flow[T]);
f[MF] = f[MF - Now] + Now * (dis[T] - h[S] + h[T]);
for (int v = T; v != S; v = From[v])
E[Pre[v]].c -= Now, E[Pre[v] ^ 1].c += Now;
for (int i = 1; i <= n; ++i)
h[i] += dis[i];
}
}
} D;
inline void CLS() {
Ecnt = 1;
D.MF = 0;
for (int i = 1; i <= n; ++i)
Fi[i] = f[i] = 0;
}
inline void Solve() {
CLS();
for (int u, v, w; m--;) {
scanf("%d%d%d", &u, &v, &w);
Add(u, v, 1, w), Add(v, u, 0, -w);
}
D.Calc(n, 1, n);
scanf("%d", &q);
for (ll u, v, k; q--;) {
scanf("%lld%lld", &u, &v);
if (u == 0 || (k = v / u) > D.MF || (v - u * k > 0 && !f[k + 1]))
puts("NaN");
else {
ll a = (v - k * u) * (f[k + 1] - f[k]) + u * f[k], b = v,
g = __gcd(a, b);
printf("%lld/%lld\n", a / g, b / g);
}
}
}
int main() {
while (~scanf("%d%d", &n, &m))
Solve();
return 0;
}