2020暑期牛客多校训练营第九场(B)Groundhog and Apple Tree(树形dp,贪心)

Groundhog and Apple Tree

原题请看这里

题目描述:

土拨鼠非常擅长爬树。
一天,土拨鼠来到一棵苹果树上。出于某种原因,他决定吃掉树上的所有苹果。苹果树上有 n {n} n个点,每个点上都有一个苹果。这些点由 n − 1 {n-1} n1条边连接(所有点都被连接)。在每个边上都有一个障碍物,这需要一定的 H P HP HP才能让 G r o u n d h o g Groundhog Groundhog跳过。如果 G r o u n d h o g Groundhog Groundhog吃了 i t h {i ^ {th }} ith在树上的苹果,他可以恢复 a i H P {a_i} HP aiHP。他可以度过没有苹果的地步。土拨鼠还可以休息一个时间来恢复 1 H P {1} HP 1HP
注意:土拨鼠的 H P HP HP不能随时为负,但可以为 0 0 0或无穷大。他只能吃一个苹果,但是每次他越过边缘时都会消耗 H P HP HP。土拨鼠没有时间跳过障碍或吃苹果。由于边缘很脆弱,因此土拨鼠最多只能穿过每个边缘两次。
现在,土拨鼠开始从树的根节点 1 {1} 1开始爬树,他的初始 H P HP HP为零。他想在经过所有点后返回到 1 {1} 1点。由于休息以恢复他的 H P HP HP非常无聊,他想问你最小的休息时间是他遍历所有要点并回到根源的时间。

输入描述:

第一行中有一个整数 T {T} T表示有 T {T} T组数据,每个数据集包含:
第一行中的整数 n {n} n表示苹果树上有 n {n} n个点。
下一行包含 n {n} n个整数, i t h {i ^ {th}} ith个整数 a i {a_i} ai表示可以通过食用 i t h {i ^ {th}} ith苹果来恢复的 H P HP HP
接下来的 n − 1 {n-1} n1行,每行包含三个整数 u i , v i , w i {u_i,v_i,w_i} uiviwi,指示在 u i {u_i} ui v i {v_i} vi之间存在一条边,障碍物消耗 w i H P {w_i} HP wiHP

输出描述:

对于每个数据集,输出一个整数,表示土拨鼠休息的最短时间。

样例输入:

1
5
4 2 1 5 7
1 2 4
1 3 5
4 2 9
5 2 3

样例输出:

23

说明:

He can traverse in the order of 131252421.

备注:

1⩽T⩽1000,1⩽n⩽10^5,∑n⩽10^6,0⩽ai,wi<2^31

思路:

树形 d p dp dp
观察题目意思,我们发现遍历整棵树其实就是从根节点出发遍历每一个子树,最后回到根节点,对于根节点的每个子树其实是一样的,没有后效性,就可以用动态规划来做,在树上跑动规,就是树形 d p dp dp啦。
分析题意我们可以想到:访问 i i i子树所需的总 H P a i HPa_i HPai是个定值,所以我们只需要考虑访问顺序所带来的影响
在遍历每个节点时,我们需要用到一个贪心思想:

  1. 优先走能加 H P HP HP的节点
  2. 优先去能加 H P HP HP多的节点
  3. 优先去 T ( T( T(最短时间 ) + H P )+HP )+HP大的节点
  4. 再去减 H P HP HP的节点

所以我们只要排一下序再按以上策略跑树形 d p dp dp即可

A C AC AC C o d e Code Code:

vector版:

#include
#define ll long long
using namespace std;
const int MAXN=1e6+5;
struct node{
	ll first,second;
	node(){}
	node(ll _fi,ll _se){
		first=_fi;
		second=_se;
	}
}dp[MAXN];
bool cmp(node x,node y){
	if(x.second>=x.first){
		if(y.second<y.first) return true;
		return x.first<y.first;
	}
	else{
		if(y.second>=y.first) return false;
		return x.second>y.second;
	}
}//贪心排序
vector<node> vec[MAXN];
int t,n,a[MAXN];
ll minn,now;
void get_ans(int pos,int fa){
	vector<node> tor;
	for(int i=0;i<vec[pos].size();++i){
		node v=vec[pos][i];
		if(v.first==fa) continue;
		get_ans(v.first,pos);
		dp[v.first].first+=v.second;
		dp[v.first].second-=v.second;
		if(dp[v.first].second<0)
			dp[v.first]=node(dp[v.first].first-dp[v.first].second,0);
		tor.push_back(dp[v.first]);
	}
	sort(tor.begin(),tor.end(),cmp);
	minn=now=a[pos];
	for(int i=0;i<tor.size();++i){
		node v=tor[i];
		minn=min(minn,now-v.first);
		now+=v.second-v.first;
	}
	if(minn>=0) dp[pos]=node(0,now);
	else dp[pos]=node(-minn,now-minn);
}
ll u,v,dis;
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;++i){
			scanf("%d",a+i);
			vec[i].clear();
		}
		for(int i=1;i<n;++i){
			scanf("%lld%lld%lld",&u,&v,&dis);
			vec[u].push_back(node(v,dis));
			vec[v].push_back(node(u,dis));
		}
		get_ans(1,-1);
		printf("%lld\n",dp[1].first);
	}
}

pair版:

#include
#define ll long long
using namespace std;
const int MAXN=1e6+5;
pair<ll,ll> dp[MAXN];
bool cmp(pair<ll,ll> x,pair<ll,ll> y){
	if(x.second>=x.first){
		if(y.second<y.first) return true;
		return x.first<y.first;
	}
	else{
		if(y.second>=y.first) return false;
		return x.second>y.second;
	}
}
vector<pair<ll,ll> > vec[MAXN];
int t,n,a[MAXN];
ll minn,now;
void get_ans(int pos,int fa){
	vector<pair<ll,ll> > tor;
	for(int i=0;i<vec[pos].size();++i){
		pair<ll,ll> v=vec[pos][i];
		if(v.first==fa) continue;
		get_ans(v.first,pos);
		dp[v.first]=make_pair(dp[v.first].first+v.second,dp[v.first].second-v.second);
		if(dp[v.first].second<0)
			dp[v.first]=make_pair(dp[v.first].first-dp[v.first].second,0);
		tor.push_back(dp[v.first]);
	}
	sort(tor.begin(),tor.end(),cmp);
	minn=now=a[pos];
	for(int i=0;i<tor.size();++i){
		pair<ll,ll> v=tor[i];
		minn=min(minn,now-v.first);
		now+=v.second-v.first;
	}
	if(minn>=0) dp[pos]=make_pair(0,now);
	else dp[pos]=make_pair(-minn,now-minn);
}
ll u,v,dis;
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;++i){
			scanf("%d",a+i);
			vec[i].clear();
		}
		for(int i=1;i<n;++i){
			scanf("%lld%lld%lld",&u,&v,&dis);
			vec[u].push_back(make_pair(v,dis));
			vec[v].push_back(make_pair(u,dis));
		}
		get_ans(1,-1);
		printf("%lld\n",dp[1].first);
	}
}

你可能感兴趣的:(树形dp,贪心)