E35 树形DP 积蓄程度

视频链接:https://www.bilibili.com/video/BV1GK4y1L7wc/

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=200010,INF=0x3f3f3f3f;
int h[N],to[N*2],w[N*2],ne[N*2],tot;  //邻接表
int d[N];   //d[i]记录从i点向下流出的最大流量
int f[N];   //f[i]记录从i点向外流出的最大流量
int deg[N]; //deg[i]记录点i的度数

void add(int a, int b, int c){
  to[++tot]=b,w[tot]=c,ne[tot]=h[a],h[a]=tot;
}
int dfs_d(int u, int fa){ //从叶点向上递推,获取u点的下流量 
  for(int i=h[u];i;i=ne[i]){
    int v=to[i];
    if(v==fa) continue;   //避免向上查找 
    int s=dfs_d(v,u);     //返回v点的下流量 
    d[u]+=min(w[i], s);   //累加u点的下流量 
  } 
  if(deg[u]==1) return INF; //特判叶的情况 
  return d[u];              //返回u点的下流量 
}
void dfs_f(int u, int fa){ //从根点向下递推,获取v点的全流量
  for(int i=h[u];i;i=ne[i]){
    int v=to[i];
    if(v==fa) continue;       
    if(deg[u]==1) f[v]=d[v]+w[i]; //特判根的情况 
    else f[v]=d[v]+min(w[i],f[u]-min(w[i],d[v])); 
    dfs_f(v, u);
  }
}
int main(){
  int t, n;
  scanf("%d", &t);
  while(t--){
    scanf("%d", &n);
    tot = 0;
    memset(h, 0, sizeof h);
    memset(d, 0, sizeof d);  
    memset(f, 0, sizeof f);     
    memset(deg, 0, sizeof deg);
    for(int i=1; i<n; i++){
      int a, b, c;
      scanf("%d%d%d", &a, &b, &c);
      add(a, b, c), add(b, a, c);
      deg[a]++, deg[b]++;
    }
    
    dfs_d(1,-1);  //向上递推下流量 
    f[1]=d[1];    //根只有向下的流量 
    dfs_f(1,-1);  //向下递推全流量 
    int ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,f[i]);
    printf("%d\n",ans);
  }
  return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=200010,INF=0x3f3f3f3f;
int h[N],to[N*2],w[N*2],ne[N*2],tot; //邻接表 
int d[N];     //d[u]记录从u点向下流出的最大流量 
int up[N];    //up[u]记录从u点向上流出的最大流量 
int deg[N];   //deg[i]记录点i的度数 

void add(int a, int b, int c){
  to[++tot]=b,w[tot]=c,ne[tot]=h[a],h[a]=tot;
}
int dfs_d(int u, int fa){ //从叶点开始向上递推u点的下流量 
  for(int i=h[u];i;i=ne[i]){
    int v=to[i];
    if(v==fa) continue;
    int s=dfs_d(v,u);     //返回v点的下流量 
    d[u]+=min(w[i], s);   //累加u点的下流量 
  } 
  if(deg[u]==1) return w[h[u]]; //若u是叶 
  return d[u];                  //返回u点的下流量 
}
void dfs_up(int u, int fa){ //从根点开始向下递推v点的上流量
  for(int i=h[u];i;i=ne[i]){
    int v=to[i];
    if(v==fa) continue;
    if(deg[u]==1) up[v]=w[i];   
    else if(deg[v]==1) up[v]=min(w[i],d[u]-w[i]+up[u]);
    else up[v]=min(d[v],min(d[u]-min(d[v],w[i])+up[u],w[i]));
    dfs_up(v, u);
  }
}
int main(){
  int t, n;
  scanf("%d", &t);
  while(t--){
    scanf("%d", &n);
    tot = 0;
    memset(h, 0, sizeof h);  
    memset(d, 0, sizeof d);  
    memset(up, 0, sizeof up);     
    memset(deg, 0, sizeof deg);
    for(int i=1; i<n; i++){
      int a, b, c;
      scanf("%d%d%d", &a, &b, &c);
      add(a, b, c), add(b, a, c);
      deg[a]++, deg[b]++;
    }
    
    dfs_d(1,-1);  //向上递推下流量  
    up[1]=0;      //根的上流量为0 
    dfs_up(1,-1); //向下递推上流量
    int ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,up[i]+d[i]);
    printf("%d\n",ans);
  }
  return 0;
}

 

posted @ 2023-04-10 10:20  董晓  阅读(317)  评论(0编辑  收藏  举报