树形DP HDU 6201

transaction transaction transaction

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 147    Accepted Submission(s): 67


Problem Description
Kelukin is a businessman. Every day, he travels around cities to do some business. On August 17th, in memory of a great man, citizens will read a book named "the Man Who Changed China". Of course, Kelukin wouldn't miss this chance to make money, but he doesn't have this book. So he has to choose two city to buy and sell. 
As we know, the price of this book was different in each city. It is  ai   yuan  in  i t  city. Kelukin will take taxi, whose price is  1 yuan  per km and this fare cannot be ignored.
There are  n1  roads connecting  n  cities. Kelukin can choose any city to start his travel. He want to know the maximum money he can get.
 

Input
The first line contains an integer  T  ( 1T10 ) , the number of test cases. 
For each test case:
first line contains an integer  n  ( 2n100000 ) means the number of cities;
second line contains  n  numbers, the  i th  number means the prices in  i th  city;  (1Price10000)  
then follows  n1  lines, each contains three numbers  x y  and  z  which means there exists a road between  x  and  y , the distance is  z km   (1z1000)
 

Output
For each test case, output a single number in a line: the maximum money he can get.
 

Sample Input
  
  
1 4 10 40 15 30 1 2 30 1 3 2 3 4 10
 

Sample Output
  
  
8
 

题意 : 在一棵树上有点和边,点有点权值,边有边权值。然后点权值代表某个点书的价格,边权值代表走过这条边所需要的花费,然后现在你可以在一个点买书,然后去另一个点卖书,问最多能赚多少钱

思路:也就是说找两个点,大的点减小的点再减中间路径权值,找最大值

我们就只需要考虑每个点到它的子树里的最大值,从叶子节点一直找到根节点就可以了

所以是一个状态的转移

1.在叶子节点u的时候,它的子树就是有它本身,所以它卖书的最小花费就是 val[u] ,而卖书的最大价值也是 val[u]

所以叶子节点的答案就是 最大卖价 - 最小花费 = 0

2.向上回溯到它的父亲节点 u ,此刻叶子节点是 v , u v 间的距离是 w ,那么如果在 u 点买书和卖书,最小话费和最大价值都是 val[u] ,所以就要从前状态找更小花费和更大价值,如果 u 点的花费 <  v 点花费 + 路费 w,那么自然是在u点买划算一些,而卖书自然的话,如果 u 的价格 > v点价格 - 路费 w 的话,就应该在 u 点卖,因为 u 点要么做买书位置,要么做卖书位置, 或者都不做,都不做的时候答案不会更新。

3. dp[ i ] [ j ]  中 , i 表示某点下标, j = 1表示该点卖书的最大值,j = 0 表示该点买书的最小值,然后每次都把最小状态赋值给它,父亲节点就能通过儿子节点的状态完整整个子树里的最优解了。

dp[i][0] = min(dp[i][0],dp[v][0] + w); 表示该点更新为最小花费

dp[i][1] = max(dp[i][1],dp[v][1] - w); 表示该点更新为最大价值

有可能同时更新为   dp[v][0] + w,和 dp[v][1] - w,但是答案不会更新为更大,因为此时会减2次 w,但是这个状态是需要保留的,因为更上方的点,到达 v 点的时候距离都得多上这一条 w,所以它是没有错的

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector> 
using namespace std;
#define maxn 100005
#define ll long long
#define mem(a,x) memset(a,x,sizeof(a))
const ll inf = (1ll) << 60;

struct node{
	int v,w;
	node(int v_,int w_) : v(v_),w(w_){}
};

int dp[maxn][2];
int val[maxn];
vector<node>vec[maxn];
int n,ans;

void add(int u,int v,int w){
	vec[u].push_back(node(v,w));
}

void treedp(int u,int pre){
	dp[u][0] = dp[u][1] = val[u];
	int sz = vec[u].size();
	for(int i = 0;i < sz;i++){
		int v = vec[u][i].v;
		int w = vec[u][i].w;
		if(v == pre)
			continue;
		treedp(v,u);
		dp[u][0] = min(dp[u][0],dp[v][0] + w);
		dp[u][1] = max(dp[u][1],dp[v][1] - w);
	}
	ans = max(ans,dp[u][1] - dp[u][0]);
}

int main(){
	int u,v,w,t;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i = 1;i <= n;i++){
			scanf("%d",&val[i]);
			vec[i].clear();
		}
		for(int i = 1;i < n;i++){
			scanf("%d %d %d",&u,&v,&w);
			add(u,v,w);
			add(v,u,w);
		}
		ans = 0;
		treedp(1,-1);
		printf("%d\n",ans);
	}	
} 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值