zoukankan      html  css  js  c++  java
  • 【树形dp】A000_AW_积蓄程度 & 计算机(换根dp / 3×dfs)

    有一个树形的水系,由 N-1 条河道和 N 个交叉点组成。
    我们可以把交叉点看作树中的节点,编号为 1~N,河道则看作树中的无向边。
    每条河道都有一个容量,连接 x 与 y 的河道的容量记为 c(x,y)。
    河道中单位时间流过的水量不能超过河道的容量。
    有一个节点是整个水系的发源地,可以源源不断地流出水,我们称之为源点。
    除了源点之外,树中所有度数为 1 的节点都是入海口,可以吸收无限多的水,我们称之为汇点。
    也就是说,水系中的水从源点出发,沿着每条河道,最终流向各个汇点。
    在整个水系稳定时,每条河道中的水都以单位时间固定的水量流向固定的方向。
    除源点和汇点之外,其余各点不贮存水,也就是流入该点的河道水量之和等于从该点流出的河道水量之和。
    整个水系的流量就定义为源点单位时间发出的水量。
    在流量不超过河道容量的前提下,求哪个点作为源点时,整个水系的流量最大,输出这个最大值。

    输入格式
    输入第一行包含整数T,表示共有T组测试数据。
    每组测试数据,第一行包含整数N。
    接下来N-1行,每行包含三个整数x,y,z,表示x,y之间存在河道,且河道容量为z。
    节点编号从1开始。
    输出格式
    每组数据输出一个结果,每个结果占一行。
    数据保证结果不超过231−1。
    数据范围
    N≤2∗105

    输入样例:
    1
    5
    1 2 11
    1 4 13
    3 4 5
    4 5 10
    输出样例:
    26
    

    方法一:自顶向下+自底向上递推

    朴素做法:假设 u->v,则从u到v的能流出的最大流量=min(w[u->v], dfs(v->v.son)),这些值可以用dfs求出,且最朴素的做法是每个点求一次这种dfs,然后从每次dfs中得到最大值

    优化做法:假设 u 是 v 的父节点,则从 \(u_i->v_i\) 流过的最大流量可以由上面的一次dfs求出,但 u 的上面还会有父节点结点,从 u 到 fa_u 的流量就等于:

    #include<bits/stdc++.h>
    using namespace std;
    struct node {
        int u,w;
    };
    const int N=2e5+5, inf=0x3f3f3f3f;
    int ans, d[N], f[N], in[N];
    vector<node> g[2*N];
    
    int dfs_d(int u, int fa) {
        int t=0;
        for (auto& to : g[u]) {
            int v=to.u, w=to.w;
            if (v!=fa) {
                dfs_d(v, u);
                t+=min(w, d[v]);
            }
        }
        if (in[u]==1) return g[u][0].w;
        else          return d[u]=t;
    }
    void dfs_f(int u, int fa) {
        for (auto& to : g[u]) {
            int v=to.u, w=to.w;
            if (v!=fa) {
                if (in[v]==1) {
                    f[v]=w+d[v];
                }else {
                    f[v]=d[v]+min(w, f[u]-min(w, d[v]));
                    dfs_f(v, u);
                }
            }
        }
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int t,n; cin>>t;
        while (t--) {
            cin>>n; memset(d,0,sizeof d), memset(f,0,sizeof f), memset(in,0,sizeof in);
            for (int i=1; i<=n; i++) g[i].clear();
            for (int i=1; i<n; i++) {
                int x,y,z; cin>>x>>y>>z;
                g[x].push_back({y,z}), g[y].push_back({x,z});
                in[x]++, in[y]++;
            }
            ans=0;f[1]=dfs_d(1, -1); //假设1为根,则f[1]=d[1]
            dfs_f(1, -1); for (int i=1; i<n; i++) ans=max(ans, f[i]);
            cout << ans << '\n';
        }
        return 0;
    }
    

    复杂度分析

    • Time\(O()\)
    • Space\(O()\)

    二、计算机

    方法一:3 × dfs

    现在请你求出第i台计算机到距离其最远的计算机的电缆长度。
    数据范围
    1≤N≤10000,
    电缆总长度不超过10^9

    
    
  • 相关阅读:
    (0.12)elasticsearch分布式集群原理(ES7.9)
    (0.9)elasticsearch分布式集群概念
    mysql分库分表【转】
    (0.11)elasticsearch常用查询,REST API的基本约定,ES增删查改
    mysql全日志自动化脚本
    Java虚拟机--类加载的过程
    Java虚拟机--运行时数据区域
    新题型|结构不良题
    恒等变形的是与非
    分形图与二阶数列
  • 原文地址:https://www.cnblogs.com/wdt1/p/13633962.html
Copyright © 2011-2022 走看看