填坑行动11-换根DP

27 篇文章 0 订阅
13 篇文章 1 订阅

文章目录

板子题

Accumulation Degree
题目描述
Trees are an important component of the natural landscape because of their prevention of erosion and the provision of a specific ather-sheltered ecosystem in and under their foliage. Trees have also been found to play an important role in producing oxygen and reducing carbon dioxide in the atmosphere, as well as moderating ground temperatures. They are also significant elements in landscaping and agriculture, both for their aesthetic appeal and their orchard crops (such as apples). Wood from trees is a common building material.
Trees also play an intimate role in many of the world’s mythologies. Many scholars are interested in finding peculiar properties about trees, such as the center of a tree, tree counting, tree coloring. A(x) is one of such properties.
A(x) (accumulation degree of node x) is defined as follows:

  1. Each edge of the tree has an positive capacity.
  2. The nodes with degree of one in the tree are named terminals.
  3. The flow of each edge can’t exceed its capacity.
  4. A(x) is the maximal flow that node x can flow to other terminal nodes.

Since it may be hard to understand the definition, an example is showed below:

A(1)=11+5+8=24
Details: 1->2 11
  1->4->3 5
  1->4->5 8(since 1->4 has capacity of 13)
A(2)=5+6=11
Details: 2->1->4->3 5
  2->1->4->5 6
A(3)=5
Details: 3->4->5 5
A(4)=11+5+10=26
Details: 4->1->2 11
  4->3 5
  4->5 10
A(5)=10
Details: 5->4->1->2 10
The accumulation degree of a tree is the maximal accumulation degree among its nodes. Here your task is to find the accumulation degree of the given trees.
输入
The first line of the input is an integer T which indicates the number of test cases. The first line of each test case is a positive integer n. Each of the following n - 1 lines contains three integers x, y, z separated by spaces, representing there is an edge between node x and node y, and the capacity of the edge is z. Nodes are numbered from 1 to n.
All the elements are nonnegative integers no more than 200000. You may assume that the test data are all tree metrics.
输出
For each test case, output the result on a single line.
样例输入

1
5
1 2 11
1 4 13
3 4 5
4 5 10

样例输出

26

大致题意:给定一颗无向带权树,权值代表两点间流量的最大值,现在要你找出一个节点作为根,向叶子节点流水(根节点的水流可以认为无限大),使整棵树的流水量最大。

题目解析

看到这道题目,第一眼的想法是做 n n n次树形DP,但是,这样的复杂度是 Θ ( n 2 ) \Theta\left(n^2\right) Θ(n2) ,超时。
这里介绍一种比较难理解的DP,叫做换根DP。
首先找一个点(最好是入度大于 1 1 1不然会有一些,设这个点为 r o o t root root)。令 g i g_i gi为以根 r o o t root root的子树的最大流量,那么我们不难得出DP式:
g u = ∑ min ⁡ ( w u , v , g v ) g_u=\sum_{}\min\left(w_{u,v},g_v\right) gu=min(wu,v,gv)
其中 v v v u u u的儿子。

然后,我们令 f i f_i fi为以 i i i作为根节点的最大水流量。
不难得到 f r o o t = g r o o t f_{root}=g_{root} froot=groot,那么其他节点呢?
例如,我们要求 f i f_i fi怎么办?
节点 i i i的子树的流量就是 g i g_i gi那么,原来节点 i i i的爸爸变成了儿子,只要算出这棵子树的流量就可以了。
i i i的父亲为 j j j,那么,以 i i i为根的子树对以根为 j j j的子树的贡献是 min ⁡ ( w i , j , g i ) \min\left(w_{i,j},g_i\right) min(wi,j,gi),那么不难得出这棵子树的贡献为:
min ⁡ ( w i , j , f j − min ⁡ ( w i , j , g i ) ) \min\left(w_{i,j},f_j-\min\left(w_{i,j},g_i\right)\right) min(wi,j,fjmin(wi,j,gi))
然后加上 g i g_i gi就可以得出 f i f_i fi了。
代码(不保证对):

#include<cstdio>
#include<cstring>
#define maxn 1000039
#define emaxn maxn<<1
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
inline int read(){
	char c=getchar();
	int flag=0;
	int sum=0;
	while((c>'9'||c<'0')&&c!='-') c=getchar();
	if(c=='-') flag=1,c=getchar();
	while('0'<=c&&c<='9'){
		sum=(sum<<1)+(sum<<3)+(c^48);
		c=getchar();
	}
	if(flag) return -sum;
	return sum;
}
int head[maxn],nex[emaxn],to[emaxn],w[emaxn],k;
#define add(x,y,z) nex[++k]=head[x];\
head[x]=k;\
to[k]=y;\
w[k]=z;//链式前向星 
int T,n,x,y,z,root;
int f[maxn],g[maxn];
//gi 表示 根节点为 i 的子树的答案
//fi 表示 根节点为 i 的答案 
void dfs1(int pre,int rt){//得到gi 
	int sum=0;
	g[rt]=0;
	for(int i=head[rt];i;i=nex[i])
		if(to[i]!=pre){
			dfs1(rt,to[i]);
			if(g[to[i]]!=0)
				g[rt]+=min(w[i],g[to[i]]);
			else g[rt]+=w[i];
		}
	return;
}
void dfs2(int pre,int rt){//得到hi 
	for(int i=head[rt];i;i=nex[i])
		if(to[i]!=pre){
			f[to[i]]=g[to[i]]+min(f[rt]-min(g[to[i]],w[i]),w[i]);
			dfs2(rt,to[i]);
		}
	return;
}
int in[maxn];
int main(){
	T=read();
	while(T--){
		memset(head,0,sizeof(head));
		n=read();
		for(int i=1;i<n;i++) {
			x=read();
			y=read();
			z=read();
			add(x,y,z);
			add(y,x,z);
			in[x]++;
			in[y]++;
		}//读入 
		root=1;
		for(int i=1;i<=n;i++)
			if(in[i]>1){
	    		root=i;
				break;
			}
		dfs1(0,root);
		f[root]=g[root];
		dfs2(0,root);
		int maxx=-1e10;
		for(int i=1;i<=n;i++)
			if(f[i]>maxx) maxx=f[i];
		printf("%d\n",maxx);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值