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;
	}
	
}

 

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