日常训练 20170605 费用流

来源:互联网 发布:淘宝有货到付款的吗 编辑:程序博客网 时间:2024/06/11 12:42

对于一张给定的运输网络,Alice 先确定一个最大流,如果有多种解,Alice 可以任选一种;之后 Bob 在每条边上分配单位花费(单位花费必须是非负实数),要求所有边的单位花费之和等于 P 。总费用等于每一条边的实际流量乘以该边的单位花费。

需要注意到,Bob 在分配单位花费之前,已经知道 Alice 所给出的最大流方案。

现茌 Alice 希望总费用尽量小,而 Bob 希望总费用尽量大。我们想知道,如果两个人都执行最优策略,最大流的值和总费用分别为多少。

为了简化问题,我们假设源点 S 是点 1,汇点 T 是点 N

N100M1000 所有点的编号在 1N 范围内。150000 , 1P10。给定运输网络中不会有起点和终点相同的边。

题解:显然 Bob 会把所有费用都放在 Alice 流量最大的一条边上,那么我们只要知道 Alice 最大流流量最大的边最小是多少,我们二分一下上界,就变成判定性问题了。然而一直卡在 70 是因为虽然最大流一定是整数,但最大流的边不一定都要是整数,所以二分要在小数范围内二分。

#include<bits/stdc++.h>const int N = 105;const int M = 1050;const double INF = 1e8;const double eps = 1e-5;template <typename T> void read(T &x) {    x = 0; char c = getchar();    for (; !isdigit(c); c = getchar());    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';}int n, m, con, S, T, a[M], b[M], first[N], s, q[N], h[N], cur[N], MAX_FLOW, shit;double c[M];struct edge {    int y, next;    double v;}mp[M*2];void ins(int x, int y, double v) {    //printf("ins x=%d y=%d v=%d\n", x, y, v);    mp[++s] = (edge) {y, first[x], v}; first[x] = s;    mp[++s] = (edge) {x, first[y], 0}; first[y] = s;}void build(double UP) {    memset(first, 0, sizeof(first)); s = 1;    for (int i=1; i <= m; i++)        ins(a[i], b[i], std::min(c[i], UP));}bool bfs() {    for (int i=1; i <= N; i++)        h[i] = 0, cur[i] = first[i];    int head = 1, tail = 1;    h[q[head] = S] = 1;    for (int x=q[head]; head <= tail; x=q[++head])        for (int t=first[x]; t; t=mp[t].next)            if (mp[t].v > eps && !h[mp[t].y]){                h[mp[t].y] = h[x] + 1,                q[++tail] = mp[t].y;                if (mp[t].y == T) return 1;            }    return 0;}double dfs(int x, double f) {    if (x == T) return f;    double used = 0, b;    for (int t=cur[x]; t; t=cur[x]=mp[t].next)        if (h[x] + 1 == h[mp[t].y]) {            b = dfs(mp[t].y, std::min(mp[t].v, f - used));            mp[t].v -= b;            mp[t^1].v += b;            used += b;            if (fabs(used - f) < eps) return used;        }    h[x] = -1;    return used;}double Dinic(double UP) {    build(UP);    double ret = 0;    while (bfs()) ret += dfs(S, INF);    return ret;}int main() {    scanf("%d%d%d", &n, &m, &con);    for (int i=1; i <= m; i++)        read(a[i]), read(b[i]), scanf("%lf", &c[i]);    S = 1, T = n;    printf("%d\n", MAX_FLOW = (int)Dinic(INF));    double l = 0, r = INF;    while (l + eps < r) {        double mid = (l + r) / 2;        if (fabs(Dinic(mid) - MAX_FLOW) < eps)            r = mid;        else            l = mid;    }    printf("%.3f\n", l * con);    return 0;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 亚麻衣服刺皮肤怎么办 自热米饭不熟怎么办 孕妇用了微波炉怎么办 蛋挞变软了怎么办 外卖炒面坨了怎么办 手机发热充电慢怎么办 饭盒盖子松了怎么办 饭盒盖子盖不住怎么办 饭盒盖子吸不住怎么办 饭盒盖子变形了怎么办 饭盒盖子凹进去怎么办 饭盒盖吸不住怎么办 饭盒微波炉加热后打不开怎么办 微波炉加热饭盒打不开怎么办 塑料饭盒加热后打不开怎么办 真空锅锅盖打不开怎么办 玻璃真空水壶打不开怎么办 保温饭盒盖子打不开怎么办 饭盒盖章松了怎么办 电压力锅卡住了怎么办 铁的饭盒打不开怎么办 微波炉饭盒盖子打不开怎么办 微波炉盖子吸住了怎么办 剩下的糯米饭怎么办 饭盒微波加热打不开怎么办 微波炉触屏不灵怎么办 微波炉旋钮坏了怎么办 微波炉蒸馒头硬怎么办 小猫两天不吃饭怎么办 减肥吃了巧乐兹怎么办 孕妇吃了点蟹籽怎么办 做寿司没有肉松怎么办 做寿司没有海苔怎么办 孩子不爱吃早餐怎么办 早上不想吃早餐怎么办 早上来不及吃早餐怎么办 早餐吃撑了怎么办 减肥吃撑了怎么办 哺乳吃爆米花了怎么办 干吃方便面后怎么办 吃了牛奶上火怎么办