反复横跳

思路

首先假设固定起始点分别为 , ,设 为所有边权之和,通过贪心可以发现,当完成任务时,除起点到终点的这条路径只经历一次外,其余每条边都要经历两次时路径和最短,此时答案为 表示 两点间的路径和)。当 最大时答案最小,由此可以推出,当选择在树上最长路径的一端作为起点,另一端作为终止点时,所经历的路径最短。
可以通过两次 求出树上最长路径。
时间复杂度:

Code

/**
 * struct Point {
 *  int x;
 *  int y;
 * };
 */

class Solution {
#define maxn 100010
private:
    vector<pair<int,int>> g[maxn];

public:
    /**
     * 最短距离
     * @param n int整型
     * @param Edge Point类vector
     * @param val int整型vector
     * @return long长整型
     */
    void dfs1(int x, int fa, long long sum, int &point, long long &dis) {
        if (sum > dis) {
            point = x;
            dis = sum;
        }
        for (auto cur: g[x]) {
            int v = cur.first, w = cur.second;
            if (v == fa) continue;
            dfs1(v, x, sum + w, point, dis);
        }
    }

    long long dfs2(int x, int fa = 0) {
        long long res = 0;
        for (auto cur: g[x]) {
            int v = cur.first, w = cur.second;
            if (v == fa) continue;
            res = max(res, dfs2(v, x) + w);
        }
        return res;
    }

    long long solve(int n, vector<Point>& Edge, vector<int>& val) {
        // write code here
        for (int i = 1; i <= n; ++i)
            g[i].clear();
        long long ans = 0;

        for (int i = 1; i < n; ++i) {
            g[Edge[i-1].x].push_back({Edge[i-1].y, val[i-1]});
            g[Edge[i-1].y].push_back({Edge[i-1].x, val[i-1]});
            ans += val[i-1];
        }

        ans <<= 1;
        int point = 1;
        long long dis = 0;
        dfs1(1, 0, 0, point, dis);
        // cout << "Ponit: " << point << endl;
        ans -= dfs2(point, 0);

        return ans;
    }
};
全部评论

相关推荐

尊嘟假嘟点击就送:加v细说,问题很大
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务