AcWing 第七周第三题 题解
3760. 最大剩余油量
一个国家由 n 个城市组成,这 n 个城市由 n−1 条双向道路连接,呈一个树形结构。
每个城市都设有加油站,在第 i 个城市可以购买 wi 升汽油。
汽车在道路上行驶,毫无疑问也会消耗汽油,每条道路的具体耗油量也会给出。
现在,需要制定一条汽车的行进路线,从任意城市 s 出发,经过一条简单路径,到达任意城市 e 结束。
注意,行进路线也可以只包含一个城市(也就是哪都没去)。
汽车初始时油箱是空的,但是可以在路线中经过的每个城市购买汽油,包括开始城市和最终城市。
如果在一条行进路线中,汽车沿一条道路从某一城市开往另一城市时,现有油量小于该条道路所需油量,那么就说明这条行进路线行不通。
请问,在保证行进路线合理的情况下,汽车在抵达最终城市后,可以剩余的最大油量是多少?
再次提醒,汽车在最终城市也可以加油。
输入格式
第一行包含整数 n。
第二行包含 n 个整数 w1,w2,…,wn。
接下来 n−1 行,每行包含三个整数 u,v,c,表示城市 u 和城市 v 之间存在一条双向道路,耗油量为 c。
输出格式
一个整数,表示可能的最大剩余油量。
数据范围
前三个测试点满足,1≤n≤5。
所有测试点满足,1≤n≤3×105,0≤wi≤109,1≤u,v≤n,1≤c≤109,u≠v。
输入样例1:
3
1 3 3
1 2 2
1 3 2
输出样例1:
3
输入样例2:
5
6 3 2 5 0
1 2 10
2 3 3
2 4 1
1 5 1
输出样例2:
7
题目意思还是很好理解的,就是给你一个树是要你求最大的树的直径,通过枚举来找出最优路径,找到最高点。树形dp 最高点的路径长度为该点的权值加上以两个子节点为路径最高点的路径长度,以此去递归(每种子情况)。
解题方法:第一种两遍DFS,第二种方法树形dp。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
int v,w;//v代表son节点,w代表该点的权值
};
const int N=300010;
ll ans=0;
int n,v[N];
vector <node> G[N];
ll dfs(int u,int father){
ll max1=0,max2=0;//max1为子节点的最大路径,max2为子节点的次最大路径
for(int i=0;i<G[u].size();i++){
int t=G[u][i].v;//与u相连的子节点
if(t==father) continue;//防止陷入循环,找过了又找
ll d=dfs(t,u);//递归子节点的最大路径长度
if(d<G[u][i].w) continue;
d-=G[u][i].w;
if(d>=max1) max2=max1,max1=d;//更新
else if(d>max2) max2=d;
}
ans = max (ans, max1+max2+v[u]);
return max1+v[u];//以u为根结点的树,能得到的最大值
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&v[i]);
}
for(int i=0;i<n-1;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
node d1;
d1.v=b;
d1.w=c;
G[a].push_back(d1);
d1.v=a;
G[b].push_back(d1);
}
ans=max(ans,dfs(1,-1));
printf("%lld\n",ans);
return 0;
}