1. 程式人生 > 其它 >AcWing 3760. 最大剩餘油量(樹的最長路徑)

AcWing 3760. 最大剩餘油量(樹的最長路徑)

題目

一個國家由 n 個城市組成,這 n 個城市由 n−1 條雙向道路連線,呈一個樹形結構。

每個城市都設有加油站,在第 i 個城市可以購買 wi 升汽油。

汽車在道路上行駛,毫無疑問也會消耗汽油,每條道路的具體耗油量也會給出。

現在,需要制定一條汽車的行進路線,從任意城市 s 出發,經過一條簡單路徑,到達任意城市 e 結束。

注意,行進路線也可以只包含一個城市(也就是哪都沒去)。

汽車初始時油箱是空的,但是可以在路線中經過的每個城市購買汽油,包括開始城市和最終城市。

如果在一條行進路線中,汽車沿一條道路從某一城市開往另一城市時,現有油量小於該條道路所需油量,那麼就說明這條行進路線行不通。

請問,在保證行進路線合理的情況下,汽車在抵達最終城市後,可以剩餘的最大油量是多少?

再次提醒,汽車在最終城市也可以加油。

輸入輸出

輸入:第一行包含整數 n。

第二行包含 n 個整數 w1,w2,…,wn。

接下來 n−1 行,每行包含三個整數 u,v,c,表示城市 u 和城市 v 之間存在一條雙向道路,耗油量為 c。
輸出:一個整數,表示可能的最大剩餘油量。

思路

這道題是選出一條路徑使最大剩餘油量最大,即樹的最長路徑(樹的直徑)問題。點權為正,邊權為負。
可以列舉一條路徑的最高點,該點的最長路徑由根節點的點權+子樹的最長長度+子樹的次長長度。用遞迴來做,遞迴返回的是子樹往下的最長長度,計算出後,更新最長路徑長度。寫的太混亂了

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 300010;
typedef long long LL;

int tot;
int head[N << 1],ver[N << 1], nxt[N << 1],edge[N << 1];
int w[N];
LL ans;
void add(int u, int v, int c)  // 新增一條邊a->b
{
    ver[++tot] = v; nxt[tot] = head[u]; head[u] = tot; edge[tot] = c;
}

LL dfs(int u,int fa){
    LL max1=0,max2=0;   //以u為根節點的子樹中最大的長度和次大的長度
    for(int i = head[u];i;i = nxt[i]){
        int v = ver[i];
        if(v == fa) continue;
        LL d = dfs(v,u);    //d是以v為根節點的子樹的最長路徑
        if(d < edge[i]) continue;
        d -= edge[i];  //走子樹到根節點需要耗費油量
        if(d >= max1) max2 = max1,max1 = d; //先更新max2,再更新max1
        else if(d > max2) max2 = d;
    }
    ans = max(ans, max1 + max2 + w[u]);
    return max1 + w[u]; //返回的是以u為根節點的最長路徑
}

int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i ++ )  cin >> w[i];
    for (int i = 0; i < n-1; i ++ ){
        int u,v,c;
        cin >> u >> v >> c;
        add(u, v, c);
        add(v, u, c);
    }
    dfs(1,0);
    cout << ans;
}

作者:inss!w! 出處:https://www.cnblogs.com/Hfolsvh/ 版權宣告:本部落格所有文章除特別宣告外,均採用 BY-NC-SA 許可協議。轉載請註明出處!