HDU 2196 Computer(树形DP) 入门模板

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sdz20172133/article/details/82952299

Computer

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 34313    Accepted Submission(s): 5345

 

Problem Description

A school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information.

http://acm.hdu.edu.cn/../../../data/images/C128-1005-1.JPG



Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.

 

 

Input

Input file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.

 

 

Output

For each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).

 

 

Sample Input

5

1 1

2 1

3 1

1 1

 

 

Sample Output

3

2

3

4

4

 

 

Author

scnu

 

 

Recommend

lcy   |   We have carefully selected several similar problems for you:  1561 1011 3456 1520 2242 

 

算法分析

求一个树中所有节点能到达的最远距离f[i]。要用两个dfs。

首先第一个dfs求出所有每个节点i在其子树中的正向最大距离(dp[i][0])和正向次大距离(dp[i][1])(如果i节点在子树中最大距离经过了2号儿子,那么次大距离就是不经过2号儿子的最大距离)。

由上步我们获得了正向最大距离,正向次大距离和最大距离的儿子节点标记。画图可以知道我们建立的这棵树,i节点的最远距离只有两种选择:i节点所在子树的最大距离,或者i节点连接它的父节点所能到达的最大距离。(即前者往下走,后者先往上走之后很可能也往下走)

所以我们只要求出反向最大距离dp[i][2](即i节点往它的父节点走所能到达的最大距离)就可以知道i节点在整个树中能走的最大距离了。

dp[i][2]求法:i节点往它的父节j点走,如果它的父节点的正向最大距离不经过i的话,那么dp[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向最大距离+ W[i][j].

如果它的父节点的正向最大距离经过i的话,那么dp[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向次大距离+ W[i][j].

上面就是dfs2要求的值。最终f[i] = max(dp[i][0],dp[i][2])

思路参考:https://blog.csdn.net/u013480600/article/details/21831363

代码不一样,这个简单些

代码实现:

#include<bits/stdc++.h>
using namespace std;
const int N=10010;
struct node
{
	int v;//终端点
    int next;//下一条同样起点的边号
    int w;//权值
}edge[N*2];///无向边,2倍
int head[N];///head[u]=i表示以u为起点的所有边中的第一条边是 i号边
int tot;  ///总边数
void add(int u,int v,int w)
{
	edge[tot].v=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int dp[N][3];
void dfs1(int u,int fa)   ///求出每个节点子树下的最大距离和次大距离
{
	 for(int i=head[u];i!=-1;i=edge[i].next)
	 {
	 	int v= edge[i].v;
	    dfs1(v,u);
	    if(fa==v) continue;
	    
	    int t=dp[v][0]+edge[i].w;
	    if(t>dp[u][0])
		{
			dp[u][1]=dp[u][0]; ///原先次短变最短
			dp[u][0]=t;        ///更新最短
		}
		else if(t>dp[u][1])
			dp[u][1]=t;
	 }
}
 void dfs2(int u,int fa)   ///求每一个结点的反向最大距离
 {
 	for(int i=head[u];i!=-1;i=edge[i].next)
	 {
	 	int v= edge[i].v;
	    if(fa==v) continue;
	    
	    if(dp[u][0]==dp[v][0]+edge[i].w)
		{
		 dp[v][2]=max(dp[u][1],dp[u][2])+edge[i].w;
		}
		else
		{
		dp[v][2]=max(dp[u][0],dp[u][2])+edge[i].w;	
		}
		dfs2(v,u);
	 }
	 
 }
int main()
{
  int n;
  while(~scanf("%d",&n))
  {
  	memset(head,-1,sizeof(head));
    memset(dp,0,sizeof(dp));
  	tot=0;
  	for(int v=2;v<=n;v++)
	{
		int u,w;
		scanf("%d%d",&u,&w);
		add(u,v,w);
	}
  	dfs1(1,-1);
  	dfs2(1,-1);
  	 for(int i=1;i<=n;i++)
	printf("%d\n",max(dp[i][0],dp[i][2]));

  }
  
  return 0;
}

双向图:

#include<bits/stdc++.h>
using namespace std;
const int N=10010;
struct node
{
	int v;//终端点
    int next;//下一条同样起点的边号
    int w;//权值
}edge[N*2];///无向边,2倍
int head[N];///head[u]=i表示以u为起点的所有边中的第一条边是 i号边
int tot;  ///总边数
void add(int u,int v,int w)
{
	edge[tot].v=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int dp[N][3];
void dfs1(int u,int fa)   ///求出每个节点子树下的最大距离和次大距离
{
	
	if(dp[u][0]>=0) //注意建立双向图,需要有一个标志,来判断是否进入
		return ;     //单向就不用了
	dp[u][0]=0;
	 for(int i=head[u];i!=-1;i=edge[i].next)
	 {
	 	int v= edge[i].v;
	    dfs1(v,u);
	    if(fa==v) continue;
	    
	    int t=dp[v][0]+edge[i].w;
	    if(t>dp[u][0])
		{
			dp[u][1]=dp[u][0]; ///原先次短变最短
			dp[u][0]=t;        ///更新最短
		}
		else if(t>dp[u][1])
			dp[u][1]=t;
	 }
}
 void dfs2(int u,int fa)   ///求每一个结点的反向最大距离
 {
 	for(int i=head[u];i!=-1;i=edge[i].next)
	 {
	 	int v= edge[i].v;
	    if(fa==v) continue;
	    
	    if(dp[u][0]==dp[v][0]+edge[i].w)
		{
		 dp[v][2]=max(dp[u][1],dp[u][2])+edge[i].w;
		}
		else
		{
		dp[v][2]=max(dp[u][0],dp[u][2])+edge[i].w;	
		}
		dfs2(v,u);
	 }
	 
 }
int main()
{
  int n;
  while(~scanf("%d",&n))
  {
  	memset(head,-1,sizeof(head));
    memset(dp,-1,sizeof(dp));
  	tot=0;
  	for(int v=2;v<=n;v++)
	{
		int u,w;
		scanf("%d%d",&u,&w);
		add(u,v,w);
		add(v,u,w);
	}
  	dfs1(1,-1);
  	dfs2(1,-1);
  	 for(int i=1;i<=n;i++)
	printf("%d\n",max(dp[i][0],dp[i][2]));

  }
  
  return 0;
}

猜你喜欢

转载自blog.csdn.net/sdz20172133/article/details/82952299