1 条题解

  • 0
    @ 2025-8-24 22:25:19

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 岸芷汀兰
    岸芷汀兰,郁郁青青。

    搬运于2025-08-24 22:25:19,当前版本为作者最后更新于2021-07-05 10:23:48,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    一、题目:

    洛谷原题

    codeforces原题

    二、思路:

    这道题整整让我调了一个下午!一直被精度卡,后来把所有的精度全部取消就 A 了!

    现在让我们来系统梳理一下这道题的思路。

    首先可以看出,题目中的参数 vv 纯粹是迷惑人的。我们完全可以将 v×fv\times f 看成一个新流。最终求出来答案再除以 vav^a 即可。

    我们试想这样一种情况:新建一个超级源点 s\mathfrak{s},从 s\mathfrak{s} 分别向 1、2 号点连容量是无穷大的边,设从 s\mathfrak{s} 向 3 号点跑最大流得到的答案是 ZZ。那么一定有 F+W=ZF+W=Z

    最终的答案设成一个函数 f(F)=Fa(ZF)1af(F)=F^a(Z-F)^{1-a},对该函数求导,得

    $$\begin{aligned} f'(F)&=aF^{a-1}(Z-F)^{1-a}-F^a(1-a)(Z-F)^{-a}\\ &=F^a(Z-F)^{-a}\left(\dfrac{a(Z-F)}{F}-1+a\right)\\ &=F^a(Z-F)^{-a}\dfrac{aZ-F}{F} \end{aligned} $$

    则当 F<aZF<aZ 时,f(F)>0f'(F)>0;当 F>aZF>aZ 时,f(F)<0f'(F)<0。所以当 F=aZF=aZ 时,f(F)f(F) 有极大值。

    但是接下来有两个问题亟待我们去解决。

    第一个问题是我们可能无法让 FF 达到 aZaZ。设从 1 号点向 3 号点跑最大流的答案是 FmaxF_{\max},从 2 号点向 3 号点跑最大流的答案是 WmaxW_{\max}。那么,FF 的范围(或者可以理解为定义域)为 [ZWmax,Fmax][Z-W_{\max},F_{\max}]。所以我们只需要在 FF 的定义域找见距离 aZaZ 最近的值即可。设该值为 FF^*W=ZFW^*=Z-F^*

    第二个问题是,有可能 FF^* 所对应的流和 WW^* 所对应的流叠加在一起时,会造成同一根水管会有不同方向的两条流。但是,我们可以构造出一种满足题意的流。

    1. s\mathfrak{s} 向 1 号点连容量为 FF^* 的边,向 2 号点连容量是 WW^* 的边。再从 s\mathfrak{s} 向 3 号点跑最大流。
    2. 新建一张图 GG,新图边的方向为旧图中最大流的流向,容量为旧图中最大流的流量。
    3. 从新图的超级源点 s\mathfrak{s} 向 1 号点连容量为 FF^* 的边,再从 s\mathfrak{s} 向 3 号点跑最大流。此时每条边的流量就是 Flubber 的最终答案,每条边的容量减流量就是 water 的最终答案。

    显然,由于新图的每条边的流量守恒,容量也守恒,所以 water 的流量也是守恒的。而且 Flubber 的流量一定是 FF^*,water 的流量一定是 WW^*

    三、代码:

    #include <iostream> // 不要设任何的eps!
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    
    using namespace std;
    #define FILEIN(s) freopen(s, "r", stdin)
    #define FILEOUT(s) freopen(s, "w", stdout)
    #define mem(s, v) memset(s, v, sizeof s)
    
    inline int read(void) {
        int x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
        while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return f * x;
    }
    
    const int MAXN = 205, MAXM = MAXN * MAXN;
    const double INF = 1e9;
    
    int n, m, head[MAXN], tot = 1, S, T;
    int q[MAXN], cur[MAXN], d[MAXN];
    int dir[MAXM];
    double Fmax, Wmax, Z, F$, W$, ans, v, a;
    
    struct Edge {
        int y, next;
        double w;
        Edge() {}
        Edge(int _y, int _next, double _w) : y(_y), next(_next), w(_w) {}
    }e[MAXM];
    
    inline void add(int x, int y, double w) {
        e[++ tot] = Edge(y, head[x], w);
        head[x] = tot;
    }
    
    inline void connect(int x, int y, double w) {
        add(x, y, w); add(y, x, w);
    }
    
    bool bfs(void) {
        int hh = 0, tt = -1;
        q[++ tt] = S; cur[S] = head[S];
        mem(d, -1); d[S] = 0;
        while (hh <= tt) {
            int x = q[hh ++];
            for (int i = head[x]; i; i = e[i].next) {
                int y = e[i].y;
                if (e[i].w > 0 && d[y] == -1) {
                    d[y] = d[x] + 1;
                    cur[y] = head[y];
                    if (y == T) return true;
                    q[++ tt] = y;
                }
            }
        }
        return false;
    }
    
    double find(int x, double limit) {
        if (x == T) return limit;
        double flow = 0;
        for (int i = cur[x]; i && flow < limit; i = e[i].next) {
            cur[x] = i;
            int y = e[i].y;
            if (e[i].w > 0 && d[y] == d[x] + 1) {
                double t = find(y, min(e[i].w, limit - flow));
                if (t == 0) d[y] = -1;
                e[i].w -= t; e[i ^ 1].w += t; flow += t;
            }
        }
        return flow;
    }
    
    double dinic(void) {
        double r = 0, flow;
        while (bfs()) {
            if ((flow = find(S, INF)) > 0) r += flow;
        }
        return r;
    }
    
    inline void restore(void) {
        for (int i = 2; i <= tot; i += 2) {
            double mid = (e[i].w + e[i ^ 1].w) / 2.0;
            e[i].w = e[i ^ 1].w = mid;
        }
    }
    
    int main() {
        n = read(); m = read(); scanf("%lf%lf", &v, &a);
        for (int i = 1; i <= m; ++ i) {
            int x = read(), y = read();
            double w; scanf("%lf", &w);
            connect(x, y, w);
        }
        S = 1; T = 3;
        Fmax = dinic(); restore();
    
        S = 2;
        Wmax = dinic(); restore();
    
        S = n + 1; connect(S, 1, INF); connect(S, 2, INF);
        Z = dinic(); restore();
    
        if (Z - Wmax > a * Z) F$ = Z - Wmax;
        else if (Fmax < a * Z) F$ = Fmax;
        else F$ = a * Z;
        W$ = Z - F$;
    
        ans = pow(F$, a) * pow(W$, 1 - a);
        ans /= pow(v, a);
    
        for (int i = head[n + 1]; i; i = e[i].next) {
            int y = e[i].y;
            if (y == 1) e[i].w = F$, e[i ^ 1].w = 0;
            else e[i].w = W$, e[i ^ 1].w = 0;
        }
        dinic();
    
        for (int i = 2; i <= tot; i += 2) {
            double mid = (e[i].w + e[i ^ 1].w) / 2;
            if (e[i ^ 1].w > mid) { dir[i] = 1; e[i].w = e[i ^ 1].w - mid; e[i ^ 1].w = 0; }
            else { dir[i] = -1; e[i ^ 1].w = e[i].w - mid; e[i].w = 0; }
        }
        for (int i = head[n + 1]; i; i = e[i].next) {
            int y = e[i].y;
            if (y == 1) { e[i].w = F$; e[i ^ 1].w = 0; }
            else e[i].w = e[i ^ 1].w = 0;
        }
    
        S = n + 1;
        dinic();
        tot -= 4;
        for (int i = 2; i <= tot; i += 2) {
            if (dir[i] == 1)
                printf("%.8lf %.8lf\n", e[i ^ 1].w / v, e[i].w);
            else
                printf("-%.8lf -%.8lf\n", e[i].w / v, e[i ^ 1].w);
    
        }
        printf("%.8lf\n", ans);
        return 0;
    }
    
    • 1

    信息

    ID
    6086
    时间
    4500ms
    内存
    512MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者