2017年“嘉杰信息杯” 中国大学生程序设计竞赛全国邀请赛:H—Highway

题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1267

Highway

In ICPCCamp there were  n  towns conveniently numbered with  1,2,,n  connected with  (n1)  roads. The  i -th road connecting towns  ai  and  bi  has length  ci . It is guaranteed that any two cities reach each other using only roads.

Bobo would like to build  (n1)  highways so that any two towns reach each using only highways. Building a highway between towns  x  and  y  costs him  δ(x,y)  cents, where  δ(x,y)  is the length of the shortest path between towns  x  and  y  using roads.

As Bobo is rich, he would like to find the most expensive way to build the  (n1)  highways.

Input

The input contains zero or more test cases and is terminated by end-of-file. For each test case:

The first line contains an integer  n . The  i -th of the following  (n1)  lines contains three integers  ai bi  and  ci .

  • 1n105
  • 1ai,bin
  • 1ci108
  • The number of test cases does not exceed  10 .

Output

For each test case, output an integer which denotes the result.

Sample Input

5
1 2 2
1 3 1
2 4 2
3 5 1
5
1 2 2
1 4 1
3 4 1
4 5 2

Sample Output

19
15

题目大意:给你一颗已知的树,求出新建的一颗权值最大的树的权值

解题思路:树形dp,求出每个点到树其他点的最长距离再减去树中的最长路径。

将每个点的最长路径添加到新建的树中,除了树中最长的那条路径会重复一次(构成一个环),不会形成其他环,而所有的点都添加到了新建的树中,于是构成了一颗权值最大的树。

dp[u][0]:u到子树节点的最长距离,dp[u][1]:u到子树节点外其他节点的最长距离

dp[u][0]很容易在dfs中计算出来。


dp[v][1]:若v不是u子树最长路径经过的点,dp[v][1] = max( dp[u][1]+Luv , dp[u][0]+Luv )

             若v是u子树最长路径所经过的点,dp[v][1] = max( dp[u][1]+Luv , dp[u][0]+Se[u])

Se[u]带表u的子树中第二长的路径长度。

#include <cstdio>  
#include <cstring>  
#include <cmath>  
#include <iostream>  
#include <queue>
#include <set>
#include <string>
#include <stack>
#include <algorithm>
#include <map>
using namespace std;  
typedef  __int64 ll;
const int N = 100100;
const int M = 20;
const int INF = 0x3fffffff;

struct  Edge
{
	int node,len;
	Edge*next;
}m_edge[N*2];
int Ecnt;
Edge*head[N];
int vis[N],flag[N];  
ll dp[N][2],second[N];
//dp[u][0]:u到子树节点的最长距离,dp[u][1]:u到子树节点外其他节点的最长距离
//second[u]:子树节点到u的第二长路径,flag[v]:节点v的上层节点的最长路径是否经过v

void init()
{
	Ecnt = 0;
	fill( head , head+N , (Edge*)0 );
	fill( flag , flag+N , 0 );
	fill( second , second+N , 0 );
}

void mkEdge( int a , int b , int c )
{
	m_edge[Ecnt].node = a;
	m_edge[Ecnt].len = c;
	m_edge[Ecnt].next = head[b];
	head[b] = m_edge+Ecnt++;

	m_edge[Ecnt].node = b;
	m_edge[Ecnt].len = c;
	m_edge[Ecnt].next = head[a];
	head[a] = m_edge+Ecnt++;
}

ll dfs1( int u )
{
	vis[u] = true; dp[u][0] = 0;
	for( Edge*p = head[u] ; p ; p = p->next ){
		int v = p->node;
		if( !vis[v] ){
			ll w = dfs1( v );
			dp[u][0] = max( dp[u][0] , w+p->len );
		}
	}
	return dp[u][0];
}

void dfs2( int u  )
{
	vis[u] = true;
	int fg = 0;
	for( Edge*p = head[u] ; p ; p = p ->next ){
		int v = p->node;
		if( !vis[v] ){
			if( !fg && dp[u][0] == dp[v][0]+p->len ) { flag[v] = 1;fg = 1; }
			else second[u] = max( second[u] , dp[v][0]+p->len );
			dfs2( v );
		}
	}
}

void dfs3( int u )
{
	vis[u] = true;
	for( Edge*p = head[u] ; p ; p = p->next ){
		int v = p->node;
		if( !vis[v] ){
			if( !flag[v] ) dp[v][1] = max( dp[u][1]+p->len , dp[u][0]+p->len );
			else dp[v][1] = max( dp[u][1]+p->len , second[u]+p->len );
			dfs3( v );
		}
	}
}

int main()
{
	int n,a,b,c;
	while( ~scanf("%d",&n) ){
		init();
		for( int i = 0 ; i < n-1 ; ++i ){
			scanf("%d%d%d",&a,&b,&c);
			mkEdge( a , b , c );
		}
		memset( vis , 0 , sizeof(vis) );
		dfs1( 1 );
		memset( vis , 0 , sizeof(vis) );
		dfs2( 1 );
		memset( vis , 0 , sizeof(vis) );
		dfs3( 1 );
		ll rec = 0,ans = 0;
		for( int i = 1 ; i <= n ; ++i ){
			ll t = max( dp[i][0] , dp[i][1] );
			ans += t;
			rec = max( rec , t );
		}
		ans -= rec;
		printf("%I64d\n",ans);
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值