• Acwing 287.积蓄程度 (树形DP换根)


    题目

    有一个树形的水系,由 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

    思路

    这道题目有点像最大流,这题我们采用树形dp进行换根,因为他要求可能的最大水流,那么如果我们以每个点为根暴力显然超时,所以我们只需要刚开始以一个点为根求出每个点往下的最大流,然后从上往下在dfs一遍,进行dp换根。

    代码实现

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    using namespace std;
    #define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
    #define per(i,n,a) for (int i=n;i>=a;i--)
    #define MT(x,i) memset(x,i,sizeof(x) )
    #define rev(i,start,end) for (int i=0;i<end;i++)
    #define inf 0x3f3f3f3f
    #define mp(x,y) make_pair(x,y)
    #define lowbit(x) (x&-x)
    #define MOD 1000000007
    #define exp 1e-8
    #define N 1000005 
    #define fi first 
    #define se second
    #define pb push_back
    typedef long long ll;
    typedef pair<int ,int> PII;
    ll gcd (ll a,ll b) {return b?gcd (b,a%b):a; }
    inline int read() {
        char ch=getchar(); int x=0, f=1;
        while(ch<'0'||ch>'9') {
            if(ch=='-') f = -1;
            ch=getchar();
        } 
        while('0'<=ch&&ch<='9') {
            x=x*10+ch-'0';
            ch=getchar();
        }   return x*f;
    }
    
    const int maxn=2e5+5;
    vector <PII> G[maxn];
    int n;
    int ans;
    int d[maxn];
    int f[maxn];
    int deg[maxn];
    
    int dfs_d (int u,int fa) {
          if (deg[u]==1) {
              d[u]=inf;
              return d[u];
          }
          d[u]=0;
          for (auto it:G[u]) {
              int j=it.first;
              if (j==fa) continue;
              d[u]+=min (dfs_d (j,u),it.second);
          }
          return d[u];
    }
    
    void dfs_f (int u,int fa) {
       for (auto it:G[u]) {
           int j=it.first;
           if (j==fa) continue;
           if (deg[j]==1) f[j]=min (f[u]-it.second,it.second);
           else {
               f[j]=d[j]+min (f[u]-min (it.second,d[j]),it.second);
               dfs_f (j,u);
           }
       }
    }
    
    int main () {
       ios::sync_with_stdio (false);
       int t;
       cin>>t;
       while (t--) {
            scanf ("%d",&n);
            int temp,flag=0;
            rep (i,1,n) G[i].clear ();
            MT (deg,0);
            rep (i,1,n-1) {
               int a,b,c;
               a=read (), b=read (),c=read ();
               G[a].pb (mp (b,c));
               if (!flag) {
                   temp=c;
                   flag=1;
               }
               G[b].pb (mp (a,c));
               deg[a]++,deg[b]++;
            }
           
           int root=1;
           while (root<=n&&deg[root]==1) root++;
           if (root>n) {
               cout<<temp<<endl;
               continue;
           }
    
           dfs_d (root,-1);
           f[root]=d[root];
           dfs_f (root,-1);
    
           ans=0;
           rep (i,1,n) ans=max (ans,f[i]);
           printf ("%d
    ",ans);
       }
       return 0;
    }
    
    
  • 相关阅读:
    软件测试的重要性
    软件测试二三事
    白盒测试总结
    黑盒测试总结
    闰年测试以及非法输入的处理方法
    软件测试(3)-基于等价类划分的一个小例子
    第二周课堂小结以及习题思考
    软件测试人员的自身修养
    软件测试的目的和方法
    第七周学习笔记之灰盒测试
  • 原文地址:https://www.cnblogs.com/hhlya/p/13452054.html
Copyright © 2020-2023  润新知