Minimum-cost Flow - MCMF - 容量為分數時的處理
阿新 • • 發佈:2020-07-15
傳送門
給出一個無向圖,已知連線情況和每條邊上的費用。
先給出q個查詢,每次查詢規定了每條邊的容量都為\(\frac{u_i}{v_i}\),求出每次查詢時,從源點1到匯點n,流量為1的最小費用值
因為容量一樣,那麼每個增廣路的流量都是\(\frac{u_i}{v_i}\),也就是說需要\(\frac{v_i}{u_i}\)條增廣路,才能使得總流量為1
考慮擴大容量,把容量變成1,也就是說變成了原來的\(\frac{v_i}{u_i}\)倍,那麼用vector記錄每條增廣路的費用,
如果說vec.size() < \(\frac{v_i}{u_i}\),那麼也就是說無法滿足。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #define ll long long using namespace std; const int N = 5e3 + 5; const int M = 5e4 + 5; std::vector<int> vec; struct MCMF{ struct Edge{ int to, next, cap, cost; //cap容量, cost單位費用 }e[M << 1]; int head[N], tot, n; // dis[] 從源點到各點的最小費用, flow[] 從源點到各點的最小流量, pre[]為每個點的前驅,lats[]為每個點所連的前一個邊 int dis[N], pre[N], last[N], flow[N]; bool vis[N]; void init(int n){ this->n = n; tot = 1; memset(head, 0, sizeof(head)); } void add(int u, int v, int cap, int cost){ e[++tot].to = v; e[tot].cap = cap; e[tot].cost = cost; e[tot].next = head[u]; head[u] = tot; } bool spfa(int s, int t){ queue <int> q; memset(dis, 0x7f, sizeof(dis)); memset(flow, 0x7f, sizeof(flow)); memset(vis, 0, sizeof(vis)); q.push(s); vis[s] = 1; dis[s] = 0; pre[t] = -1; while (!q.empty()){ int now = q.front(); q.pop(); vis[now] = 0; for (int i = head[now]; i; i = e[i].next){ int v = e[i].to; if (e[i].cap > 0 && dis[v] > dis[now] + e[i].cost){ dis[v] = dis[now] + e[i].cost; pre[v] = now; last[v] = i; flow[v] = min(flow[now], e[i].cap); if (!vis[v]){ vis[e[i].to] = 1; q.push(e[i].to); } } } } return pre[t] != -1; } pair<int,int> mcmf(int s, int t){ int mincost = 0, maxflow = 0; while (spfa(s, t)){ //尋找增廣路 vec.push_back(dis[t]); int now = t; maxflow += flow[t]; mincost += flow[t] * dis[t]; // s到t的最小總費用乘以最小流量 while (now != s){ //從源點一直回溯到匯點 e[last[now]].cap -= flow[t]; // 正向流量減少 e[last[now] ^ 1].cap += flow[t]; // 反向流量增加 now = pre[now]; } } return make_pair(mincost, maxflow); } } G; ll gcd(ll a, ll b){ return b == 0 ? a : gcd(b, a % b); } ll sum[N]; int main(){ int n, m, s, t; while(~scanf("%d%d", &n, &m)){ G.init(n); for (int i = 1; i <= m; i++){ int u, v, cost; scanf("%d%d%d", &u, &v, &cost); G.add(u, v, 1, cost); G.add(v, u, 0, -cost); // 建立反向邊,容量為0,負花費 } vec.clear(); G.mcmf(1, n); sum[0] = 0; for(int i = 0; i < vec.size(); i++) { sum[i + 1] = sum[i] + vec[i]; } int q; scanf("%d", &q); while(q--){ int u, v; scanf("%d%d", &u, &v); int a = v / u, b = v % u; if(1ll * u * vec.size() < v) { printf("NaN\n"); continue; } ll ans = u * sum[a] + 1ll * vec[a] * b; ll d = gcd(ans, 1ll * v); printf("%lld/%lld\n", ans / d, v / d); } } return 0; }