H.Minimum-cost Flow
题目:
其实就是给出每条边的单位费用,q次查询,每次查询改变所有边的容量(所有边容量一样),问最后流出1流量的最小花费是多少?
题解:
暴力做法肯定是每次询问都改一次容量,但是肯定会超时,想想其他方法
对于题目的每次询问,每条增广路的容量为u/v,所需最大流是1,我们可以列出一个式子
cost(u/v,1) = cost(u,v)
也就是把问题变成每条容量为u,所需要的最大流为v
为了达到最大流为v的要求,肯定有a条增广路容量用完,但也肯定会有一个增广路只用了部分(假设用了b容量)0<=b<u
能得到:v = a * u + b(0<=b<u)
所以我们只需要求出前a条增广路的全部和第a+1条增广路的b容量
然后记得判断流出的流量要大于等于v才可以,不足v就输出NaN
因为跑得最小费用最大流,这样的答案一定是最优答案
代码:
#include<bits/stdc++.h>using namespace std;
#define lowbit(x) ((x)&(-x))
#define REP(i, a, n) for(int i=a;i<=(n);i++)
#define IOS ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;const int maxn = 1e5 + 10;
const int N = 1e2 + 10;
const int M = 1e3 + 10;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const int mod2 = 998244353;
const int mod3 = 1e9 + 9;
const int hash1 = 131;
const int hash2 = 13331;
const double eps = 1e-6;
int head[N], ver[M], nxt[M], edge[M], cost[M];
int tot = 1;
int d[N], incf[N], pre[N];
int vis[N];void add(int x, int y, int z, int c)
{ver[++tot] = y, edge[tot] = z, cost[tot] = c, nxt[tot] = head[x], head[x] = tot;ver[++tot] = x, edge[tot] = 0, cost[tot] = -c, nxt[tot] = head[y], head[y] = tot;
}int s, t;
vector<int> path;bool spfa()
{queue<int> q;memset(d, inf, sizeof(d));memset(vis, 0, sizeof(vis));q.push(s);d[s] = 0, vis[s] = 1;incf[s] = 1 << 30;while (!q.empty()){int x = q.front();q.pop();vis[x] = 0;for (int i = head[x]; i; i = nxt[i]){if (!edge[i])continue;int y = ver[i];if (d[y] > d[x] + cost[i]){d[y] = d[x] + cost[i];incf[y] = min(incf[x], edge[i]);pre[y] = i;if (!vis[y])vis[y] = 1, q.push(y);}}}if (d[t] == inf)return false;return d[t];
}int maxflow, ans;void update()
{path.push_back(d[t]);//记录每条增广路的花费int x = t;while (x != s){int i = pre[x];edge[i] -= incf[t];edge[i ^ 1] += incf[t];x = ver[i ^ 1];}maxflow += incf[t];ans += d[t] * incf[t];}ll sumd[N];int main()
{int n, m;while (scanf("%d%d", &n, &m) != EOF){path.clear();memset(head, 0, sizeof(head));tot = 1;for (int i = 1; i <= m; i++){int a, b, c;scanf("%d%d%d", &a, &b, &c);add(a, b, 1, c);}s = 1, t = n;while (spfa())update();for (int i = 0; i < path.size(); i++){sumd[i + 1] = sumd[i] + path[i];//前i条增广路的花费 }int q;scanf("%d", &q);int u, v;for (int i = 1; i <= q; i++){scanf("%d%d", &u, &v);if (u * path.size() < v){puts("NaN");continue;}ll a = v / u;ll b = v % u;ll ans = sumd[a] * u + path[a] * b;ll x = __gcd((ll) v, ans);printf("%lld/%lld\n", ans / x, v / x);}}return 0;
}