Luogu P3305 [SDOI2013]费用流 二分 网络流

题目链接 \(Click\) \(Here\)

非常有趣的一个题目。

关键结论:所有的单位费用应该被分配在流量最大的边上。

即:在保证最大流的前提下,使最大流量最小。这里我们采用二分的方法,每次判断让所有边的流量\(<=mid\)时是否依然有最大流,求得最小的最大流量\(*p\)即可。

为什么会有实数流量呢?其实我也不懂,不过这也造成这个题目需要把流量改成\(double\),有很多细节需要小心谨慎。。。

#include <bits/stdc++.h>
using namespace std;

const int N = 400010;
const int M = 400010;
const int INF = 0x3f3f3f3f;

int u[N], v[N], flow[N]; double f[N];

int n, m, p, cnt = -1, head[N];

struct edge {
    int nxt, to; double f;
}e[M];

void add_edge (int from, int to, double flw) {
    e[++cnt].nxt = head[from];
    e[cnt].to = to;
    e[cnt].f = flw;
    head[from] = cnt;
}

void add_len (int u, int v, double f) {
    add_edge (u, v, f);
    add_edge (v, u, 0);
}

queue <int> q;
int cur[N], deep[N];

bool bfs (int s, int t) {
    memcpy (cur, head, sizeof (head));
    memset (deep, 0x3f, sizeof (deep));
    deep[s] = 0; q.push (s);
    while (!q.empty ()) {
        int u = q.front (); q.pop ();
        for (int i = head[u]; ~i; i = e[i].nxt) {
            int v = e[i].to;
            if (deep[v] == INF && fabs (e[i].f) > 1e-8) {
                deep[v] = deep[u] + 1;
                q.push (v);
            }
        }
    }
    return deep[t] != INF;
}

double dfs (int u, int t, double lim) {
    if (u == t || fabs (lim) < 1e-8) {
        return lim;
    }
    double tmp = 0, flow = 0;
    for (int &i = cur[u]; ~i; i = e[i].nxt) {
        int v = e[i].to;
        if (deep[v] == deep[u] + 1) {
            tmp = dfs (v, t, min (lim, e[i].f));
            lim -= tmp;
            flow += tmp;
            e[i ^ 0].f -= tmp;
            e[i ^ 1].f += tmp;
            if (fabs (lim) < 1e-8) break;
        }
    }
    return flow;
} 

double Dinic (int s, int t) {
    double res = 0;
    while (bfs (s, t)) {
        res += dfs (s, t, INF);
    }
    return res;
}

double max_flow;

bool can_use (double flw) {
    cnt = -1; int s = 1, t = n;
    memset (head, -1, sizeof (head));
    for (int i = 1; i <= m; ++i) {
        add_len (u[i], v[i], min (f[i], flw));
    }
    return fabs (Dinic (s, t) - max_flow) < 1e-8;
}

int main () {
    memset (head, -1, sizeof (head));
    cin >> n >> m >> p;
    for (int i = 1; i <= m; ++i) {
        cin >> u[i] >> v[i] >> f[i];
        add_len (u[i], v[i], f[i]);
    }
    int s = 1, t = n; max_flow = Dinic (s, t);
    printf ("%.0lf\n", max_flow);
    double l = 0, r = INF;
    while (r - l > 1e-8) {
        double mid = (l + r) / 2.0;
        if (can_use (mid)) {
            r = mid;
        } else {
            l = mid;
        }
    }
    printf ("%.4lf\n", r * p);
}

原文地址:https://www.cnblogs.com/maomao9173/p/10505926.html

时间: 2024-11-10 08:32:19

Luogu P3305 [SDOI2013]费用流 二分 网络流的相关文章

【bzoj3130】[Sdoi2013]费用流 二分+网络流最大流

题目描述 Alice和Bob做游戏,给出一张有向图表示运输网络,Alice先给Bob一种最大流方案,然后Bob在所有边上分配总和等于P的非负费用.Alice希望总费用尽量小,而Bob希望总费用尽量大.求两人都采取最优策略的情况下最大流及总费用. 输入 第一行三个整数N,M,P.N表示给定运输网络中节点的数量,M表示有向边的数量,P的含义见问题描述部分.为了简化问题,我们假设源点S是点1,汇点T是点N.接下来M行,每行三个整数A,B,C,表示有一条从点A到点B的有向边,其最大流量是C. 输出 第一

P3305 [SDOI2013]费用流

题目描述 Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识. 最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量. 一个合法的网络流方案必须满足: (1)每条边的实际流量都不超过其最大流量且非负: (2)除了源点S和汇点T之外,对于其余所有点,都满足该点总流入流量等于该点总流出流量:而S点的净流出流量等于T点的净流入流量,这个值也即该网络流方案的总运输量. 最大流问题就是对于给定的运输网络,求总运输量最大的网络流方案. 上图表示了一个最大流问题

BZOJ3130 SDOI2013 费用流 二分法+网络流

题意:给定一张图,求:1.最大流  2.最大流方案中,流量最大的一条边 题解: 第一问裸题 第二问显然Bob要把所有的费用加在流量最大的边上,因此我们二分最长边,每条边的流量改为min{二分出的最大流量,当前边的流量},跑最大流检验. 注意可以是实数流量,比如说: <1,2,3> <3,2,3> <2,4,2> <2,5,2> <2,6,1> 那么加在<1,2>和<3,2>上的流量用2.5最优 #include <q

BZOJ 3130: [Sdoi2013]费用流 网络流+二分

3130: [Sdoi2013]费用流 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1230  Solved: 598[Submit][Status][Discuss] Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识.     最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案必须满足:(1)每条边的实际流量都

BZOJ3130: [Sdoi2013]费用流[最大流 实数二分]

3130: [Sdoi2013]费用流 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 960  Solved: 505[Submit][Status][Discuss] Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识.    最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案必须满足:(1)每条边的实际流量都不超

BZOJ 3130 [Sdoi2013]费用流 ——网络流

[题目分析] 很容易想到,可以把P放在流量最大的边上的时候最优. 所以二分网络流,判断什么时候可以达到最大流. 流量不一定是整数,所以需要实数二分,整数是会WA的. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> //#include <map> #include <set> #include <queue> #in

bzoj 3597 [Scoi2014] 方伯伯运椰子 - 费用流 - 二分答案

题目传送门 传送门 题目大意 给定一个费用流,每条边有一个初始流量$c_i$和单位流量费用$d_i$,增加一条边的1单位的流量需要花费$b_i$的代价而减少一条边的1单位的流量需要花费$a_i$的代价.要求最小化总费用减少量和调整次数的比值(至少调整一次). 根据基本套路,二分答案,移项,可以得到每条边的贡献. 设第$i$条边的流量变化量为$m_i$,每次变化花费的平均费用为$w_i$.那么有 $\sum c_id_i - \sum (c_i + m_i)d_i + |m_i|(w_i + mi

bzoj 3130 [Sdoi2013]费用流(二分,最大流)

Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识.    最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案必须满足:(1)每条边的实际流量都不超过其最大流量且非负:(2)除了源点S和汇点T之外,对于其余所有点,都满足该点总流入流量等于该点总流出流量:而S点的净流出流量等于T点的净流入流量,这个值也即该网络流方案的总运输量.最大流问题就是对于给定的运输网络,求总运输量最大的网络流方案.   上图表示

【二分答案】【最大流】bzoj3130 [Sdoi2013]费用流

二分最大的边的cap,记作Lim. 把所有的边的cap设为min(Lim,cap[i]). Bob一定会把单位费用加到最大边上. #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> using namespace std; #define EPS 0.000001 #define N 101 #define INF 21474