第一问模板最大流。
对于第二问,考虑如果已经确定了最大流方案,那么如何分配使得费用最大。
假设先随机分配,然后可以发现,如果两条边
e1,e2
e
1
,
e
2
,通过
e1
e
1
的流量大于通过
e2
e
2
的流量,那么如果将
e1
e
1
的费用增加
k
k
,的费用减小
k
k
(是正数),那么费用一定会更大。
按照这个贪心,得出结论:费用最大的方案为流量(不是容量)最大的边分配到的费用为
P
P
,其他的边分配到的费用为。
于是问题转化为:求一种最大流方案,使得流量最大的边的流量尽可能小。
看到是求最大值最小,因此二分答案(注意是在实数域上的二分),每次判定(设当前要判定的解为
mid
m
i
d
)时重新建图:
对于每一条边,如果原先的容量为
c
c
,则此次建图时该边的容量为。
建图后跑最大流,如果等于第一问的答案,则最优解
≤mid
≤
m
i
d
。
第二问的答案就等于上面得出的最优解乘上
P
P
<script type="math/tex" id="MathJax-Element-2003">P</script>。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Edge(u) for (int e = adj[u], v; e; e = nxt[e])
using namespace std;
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const double eps = 1e-8;
const int N = 105, M = 2018;
int n, m, P, _u[M], _v[M], _cap[M], ecnt = 1, nxt[M], adj[N], go[M], lev[N],
len, que[M];
double cap[M], Ans;
void add_edge(int u, int v, double w)
{
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; cap[ecnt] = w;
nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u; cap[ecnt] = 0;
}
bool bfs()
{
int i;
For (i, 1, n) lev[i] = -1;
lev[que[len = 1] = 1] = 0;
For (i, 1, len)
{
int u = que[i];
Edge(u) if (cap[e] > eps && lev[v = go[e]] == -1)
{
lev[que[++len] = v] = lev[u] + 1;
if (v == n) return 1;
}
}
return 0;
}
double dinic(int u, double flow)
{
if (u == n) return flow;
double res = 0, delta = 0;
Edge(u)
if (cap[e] > eps && lev[u] < lev[v = go[e]])
{
delta = dinic(v, min(cap[e], flow - res));
if (delta > eps)
{
cap[e] -= delta; cap[e ^ 1] += delta;
res += delta;
if (fabs(flow - res) <= eps) break;
}
}
if (fabs(flow - res) > eps) lev[u] = -1;
return res;
}
double solve()
{
double ans = 0;
while (bfs()) ans += dinic(1, 1e12);
return ans;
}
bool check(double mid)
{
int i; ecnt = 1;
For (i, 1, n) adj[i] = 0;
For (i, 1, m)
add_edge(_u[i], _v[i], min(1.0 * _cap[i], mid));
return fabs(Ans - solve()) <= eps;
}
int main()
{
int i, _max = 0;
n = read(); m = read(); P = read();
For (i, 1, m)
_u[i] = read(), _v[i] = read(),
_max = max(_max, _cap[i] = read()),
add_edge(_u[i], _v[i], _cap[i]);
printf("%.0lf\n", Ans = solve());
double l = 0, r = _max;
while (r - l > 1e-5)
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
printf("%.4lf\n", l * P);
return 0;
}