Groundhog and Apple Tree
题目描述:
土拨鼠非常擅长爬树。
一天,土拨鼠来到一棵苹果树上。出于某种原因,他决定吃掉树上的所有苹果。苹果树上有
个点,每个点上都有一个苹果。这些点由
条边连接(所有点都被连接)。在每个边上都有一个障碍物,这需要一定的
才能让
跳过。如果
吃了
在树上的苹果,他可以恢复
。他可以度过没有苹果的地步。土拨鼠还可以休息一个时间来恢复
。
注意:土拨鼠的
不能随时为负,但可以为
或无穷大。他只能吃一个苹果,但是每次他越过边缘时都会消耗
。土拨鼠没有时间跳过障碍或吃苹果。由于边缘很脆弱,因此土拨鼠最多只能穿过每个边缘两次。
现在,土拨鼠开始从树的根节点
开始爬树,他的初始
为零。他想在经过所有点后返回到
点。由于休息以恢复他的
非常无聊,他想问你最小的休息时间是他遍历所有要点并回到根源的时间。
输入描述:
第一行中有一个整数
表示有
组数据,每个数据集包含:
第一行中的整数
表示苹果树上有
个点。
下一行包含
个整数,
个整数
表示可以通过食用
苹果来恢复的
。
接下来的
行,每行包含三个整数
,指示在
和
之间存在一条边,障碍物消耗
。
输出描述:
对于每个数据集,输出一个整数,表示土拨鼠休息的最短时间。
样例输入:
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 1 → 3 → 1 → 2 → 5 → 2 → 4 → 2 → 1.
备注:
1⩽T⩽1000,1⩽n⩽10^5,∑n⩽10^6,0⩽ai,wi<2^31
思路:
树形
观察题目意思,我们发现遍历整棵树其实就是从根节点出发遍历每一个子树,最后回到根节点,对于根节点的每个子树其实是一样的,没有后效性,就可以用动态规划来做,在树上跑动规,就是树形
啦。
分析题意我们可以想到:访问
子树所需的总
是个定值,所以我们只需要考虑访问顺序所带来的影响
在遍历每个节点时,我们需要用到一个贪心思想:
- 优先走能加 的节点
- 优先去能加 多的节点
- 优先去 最短时间 大的节点
- 再去减 的节点
所以我们只要排一下序再按以上策略跑树形 即可
:
vector版:
#include<bits/stdc++.h>
#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<bits/stdc++.h>
#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);
}
}