POJ 3585 Accumulation Degree 树形dp

题目链接

Accumulation Degree

Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 5388   Accepted: 1309

Description

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.

Input

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 xyz 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.

Output

For each test case, output the result on a single line.
 

Sample Input

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

Sample Output

26

 

给你一棵树,每个节点作为一个源头,只有一条边的节点可以视为入海口,每条边有最大流量,问这棵树源头的最大流量。

本题是一个不定根的树,可以用“二次扫描与换根法”。

1、第一次扫描时,任选一个点为根,在“有根树”上执行一次树形dp,也就是回溯时发生的,自底向上的状态转移;

2、第二次扫描时,从刚才选出的根出发,对整棵树再进行一次dfs,每次递归前自顶向下的推导,给出换根后的结果。就是相当于把这条与“父亲”相连的边转换成与儿子相连的边,进行处理。

对于本题,我们任选一个点作为根节点,化成一棵有根树。此时每一个节点作为源点的流量是其向下走(子树)和向上走(父亲)流量之和。求子树自然一次dfs,注意u的子节点v入度为1的时候,v的子树流量为0,u直接加上u,v之间的边权即可。

此时d[x]保存的是以x为根节点的子树的流量和。

对于我们选定的根节点root,其向上走的结果为0,root作为源点最终的结果已经出来了。

第二次dfs,就是求向上走的流量,此时父亲节点的最终答案d[u]已经算好了,儿子节点还是以儿子节点为根的子树的流量和d[v],直接把父亲节点的总流量减去走以这个儿子为根节点的子树的流量,此时就是父亲节点走别的路的流量,加到儿子上即可。

注意如果父亲节点的度为1,儿子节点直接加上c[u,v](u和v之间边的边权)。

“父亲节点的总流量减去走以这个儿子为根节点的子树的流量”       d[u]-min(d[x],c[u,v])

“加到儿子上” d[v]+=min(d[u]-min(d[x],c[u,v]),c[u,v])

时刻注意边权与节点流量的取min。

 

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=2e5+10;
struct node
{
	int v,w;	
//	node (): {}
	node(int v,int w):v(v),w(w){} 
};
int in[N],d[N];
vector<node>tr[N];
void dfs1(int u,int fa)
{
	for(int i=0;i<tr[u].size();i++)
	{
		int v=tr[u][i].v;
		if(v==fa) continue;
		dfs1(v,u);
		if(in[v]==1) d[u]+=tr[u][i].w;//当儿子度为1的时候,d[y]=0,不能选d[y] 
		else d[u]+=min(tr[u][i].w,d[v]);
	}
}
void dfs2(int u,int fa)
{
	for(int i=0;i<tr[u].size();i++)
	{
		int v=tr[u][i].v;
		if(v==fa) continue;
		if(in[u]==1) d[v]+=tr[u][i].w;
		else d[v]+=min(d[u]-min(d[v],tr[u][i].w),tr[u][i].w);
		dfs2(v,u);	
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int n,x,y,z;
		cin>>n;
		for(int i=1;i<=n;i++)
			tr[i].clear();
		ms(in,0);
		ms(d,0);
		for(int i=1;i<n;i++)
		{
			cin>>x>>y>>z;
			tr[x].push_back(node(y,z));
			tr[y].push_back(node(x,z));
			in[x]++;
			in[y]++;
		}
		dfs1(1,0);
		dfs2(1,0);
		int ans=0;
		for(int i=1;i<=n;i++)
			ans=max(ans,d[i]);
		cout<<ans<<endl;
	}
	
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章