zoukankan      html  css  js  c++  java
  • $Poj3585 Accumulation Degree$ 树形$DP/$二次扫描与换根法

    Poj

    Description

     有一个树形的水系,由n-1条河道与n个交叉点组成.每条河道有一个容量,联结x与y的河道容量记为c(x,y),河道的单位时间水量不能超过它的容量.有一个结点是整个水系的发源地,可以源源不断地流出水,为源点.树中度为1的点是入海口,可以吸收无限多的水,为汇点.待整个水系稳定时,每条河道中的水都以单位时间固定的水量流向固定的方向.整个水系的流量就定义为源点单位时间发出的水量.

    求哪个点作为源点时,整个水系的流量最大.

    Sol

    最朴素的做法就是枚举源点,再树形DP,更新答案.复杂度是O(n2)的,不能接受.

    推想:某点为源点时的流量可以由其他点为源点时的流量推出

    d[x]表示x的度,f1[x]表示以x为根的树的最大流量,f2[x]表示以x为源点时水系的最大流量,y是x的子结点

    首先任意选取一个点作为源点(root),一次树形DP算出所有的f1[x]

    具体的转移: if(d[y]==1)f1[x]+=c(x,y)  else f1[x]+=min(f1[y],c(x,y))

    现在已知f2[x],可以推出f2[y]:

    f2[y]包括两个部分:

    1.流向x,(没错x由父变子hhh),这部分的流量:

    if(d[x]==1) 为c(x,y)  else 为f2[x]-min(f1[y],c(x,y))

    2.流向原来就是它的子结点的点,这部分的流量就是f1[y]

    over!

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<vector>
     5 #define Rg register
     6 #define il inline
     7 #define mem(a,b) memset(a,b,sizeof(a));
     8 #define go(i,a,b) for(Rg int i=a;i<=b;++i)
     9 using namespace std;
    10 il int read()
    11 {
    12     int x=0,y=1;char c=getchar();
    13     while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
    14     while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    15     return x*y;
    16 }
    17 const int N=200001;
    18 int T,n,ans,d[N],f1[N],f2[N];
    19 bool vis[N];
    20 struct node{int y,w;};
    21 vector<node> c[N];
    22 il void init()
    23 {
    24     ans=0;
    25     mem(vis,0);mem(d,0);mem(f1,0);mem(f2,0);
    26     go(i,1,n)c[i].clear();
    27 }
    28 il void dp1(int x)
    29 {
    30     vis[x]=1;
    31     int hhh=c[x].size()-1;
    32     go(i,0,hhh)
    33     {
    34         int y=c[x][i].y,w=c[x][i].w;
    35         if(vis[y])continue;
    36         dp1(y);
    37         if(d[y]==1)f1[x]+=w;
    38         else f1[x]+=min(f1[y],w);
    39     }
    40 }
    41 il void dp2(int x)
    42 {
    43     vis[x]=1;
    44     int hhh=c[x].size()-1;if(hhh<0)return;
    45     go(i,0,hhh)
    46     {
    47         int y=c[x][i].y,w=c[x][i].w;
    48         if(vis[y])continue;
    49         if(d[x]==1)f2[y]=f1[y]+w;
    50         else f2[y]=f1[y]+min(f2[x]-min(f1[y],w),w);
    51         dp2(y);
    52     }
    53 }
    54 int main()
    55 {
    56     T=read();
    57     while(T--)
    58     {
    59         n=read();init();
    60         go(i,1,n-1)
    61         {
    62             int x=read(),y=read(),z=read();
    63             c[x].push_back((node){y,z});c[y].push_back((node){x,z});
    64             ++d[x],++d[y];
    65         }
    66         dp1(1);
    67                 f2[1]=f1[1];mem(vis,0);
    68         dp2(1);
    69         go(i,1,n)ans=max(ans,f2[i]);
    70         printf("%d
    ",ans);
    71     }
    72     return 0;
    73 }
    74         
    View Code

     

     

    光伴随的阴影
  • 相关阅读:
    python之定时器Timer
    (转载)Python一篇学会多线程
    docker速记
    IP地址简单入门
    pycharm快捷键及一些常用设置(转载)
    python系列1_travel
    Fluter基础巩固之Dart语言详解<三>
    Fluter基础巩固之Dart语言详解<二>
    Fluter基础巩固之Dart语言详解<一>
    Java精通并发-Condition编程模式详解与分析
  • 原文地址:https://www.cnblogs.com/forward777/p/11010431.html
Copyright © 2011-2022 走看看