0x50 动态规划(0x54 树形DP)例题3:积蓄程度(题解)

题意

神仙题

【题目描述】
 有一个树形的水系,由 N-1 条河道和 N 个交叉点组成。
 我们可以把交叉点看作树中的节点,编号为 1~N,河道则看作树中的无向边。
 每条河道都有一个容量,连接 x 与 y 的河道的容量记为 c(x,y)。
 河道中单位时间流过的水量不能超过河道的容量。
 有一个节点是整个水系的发源地,可以源源不断地流出水,我们称之为源点。
 除了源点之外,树中所有度数为 1 的节点都是入海口,可以吸收无限多的水,我们称之为汇点。
 也就是说,水系中的水从源点出发,沿着每条河道,最终流向各个汇点。
 在整个水系稳定时,每条河道中的水都以单位时间固定的水量流向固定的方向。
 除源点和汇点之外,其余各点不贮存水,也就是流入该点的河道水量之和等于从该点流出的河道水量之和。
 整个水系的流量就定义为源点单位时间发出的水量。
 在流量不超过河道容量的前提下,求哪个点作为源点时,整个水系的流量最大,输出这个最大值。  
  【输入格式】
 输入第一行包含整数T,表示共有T组测试数据。
 每组测试数据,第一行包含整数N。
 接下来N-1行,每行包含三个整数x,y,z,表示x,y之间存在河道,且河道容量为z。
 节点编号从1开始。  
  【输出格式】
 每组数据输出一个结果,每个结果占一行。
 数据保证结果不超过2^31−1。  
  【数据范围】
N≤2*10^5  
  【输入样例】
1
 5
 1 2 11
 1 4 13
 3 4 5
 4 5 10   
  【输出样例】
26 

思路

我的妈呀,如果以前没做仓鼠找sugar II估计我还真做不出这道题目。

看到这种找根且还带树形DP的题目,脑子里面要马上树立一个正确的价值观,就是我们先固定一个根。

很明显,我们只要固定了一个根的话,算出他的流量不是手到擒来?

我们设(f[i])表示这棵子树以(i)为汇点的话,那么流量是多少,随便DP一下就可以算出(f[1]),同时我们又发现,我们貌似是可以(O(1))转移的!

在这里插入图片描述

把当树根为(1)的情况转移到树根为(2)的情况貌似只用(O(1)),即减去(2)(1)的贡献,然后把(1)(2)的贡献加到(2),然后我们就可以算出树根为(2)的值了,那么我们再DFS一遍不就可以(O(n))解决了吗?

当然根节点如果只有一个儿子的话那么转移到儿子后他的(f)(inf)

#include<cstdio>
#include<cstring>
#define  N  210000
#define  M  410000
#define  inf  2147483647
using  namespace  std;
struct  node
{
	int  y,c,next;
}a[M];int  len,last[N];
inline  void  ins(int  x,int  y,int  c){len++;a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;}
int  f[N]/*表示的是以1为根的话,那么这个点的水流是多少*/,dp[N]/*表示以他为根时的答案。*/;
int  siz[N],dep[N];
int  n;
inline  int  mymin(int  x,int  y){return  x<y?x:y;}
inline  int  mymax(int  x,int  y){return  x>y?x:y;}
void  dfs1(int  x,int  fa)
{
	siz[x]=1;
	for(int  k=last[x];k;k=a[k].next)
	{
		int  y=a[k].y;
		if(y!=fa)
		{
			dep[y]=dep[x]+1;
			dfs1(y,x);
			f[x]+=mymin(f[y],a[k].c);siz[x]+=siz[y];
		}
	}
	if(siz[x]==1)f[x]=inf;
}
void  dfs2(int  x,int  fa)//表示以x为根的答案。 
{
	dp[x]=f[x];//索性继承 
	for(int  k=last[x];k;k=a[k].next)
	{
		int  y=a[k].y;
		if(y!=fa)
		{
			int  now=f[x];
			if(siz[x]-siz[y]==1  &&  dep[x]==0/*在根节点*/)f[x]=inf;
			else  f[x]-=mymin(f[y],a[k].c);
			if(siz[y]==1)f[y]=mymin(f[x],a[k].c);//特判这个点是不是叶子节点 
			else  f[y]+=mymin(f[x],a[k].c);
			dfs2(y,x);
			if(siz[y]==1)f[y]=inf;
			else  f[y]-=mymin(f[x],a[k].c);
			f[x]=now;
		}
	}
}
int  main()
{
	int  T;scanf("%d",&T);
	while(T--)
	{
		len=0;memset(last,0,sizeof(last));
		memset(f,0,sizeof(f));
		memset(dp,0,sizeof(dp));//暴力初始化
		scanf("%d",&n);
		for(int  i=1;i<n;i++)
		{
			int  x,y,z;scanf("%d%d%d",&x,&y,&z);
			ins(x,y,z);ins(y,x,z);
		}
		dfs1(1,0);
		dfs2(1,0);
		int  ans=0;
		for(int  i=1;i<=n;i++)ans=mymax(dp[i],ans);
		printf("%d
",ans);
	}
	return  0;
}
原文地址:https://www.cnblogs.com/zhangjianjunab/p/11714515.html