牛客题解 水图

链接:https://ac.nowcoder.com/acm/problem/18947
来源:牛客网

题解

作者 岛田小雅

由题目中“\(n\) 个点 \(n-1\) 条边的无向连通图”可得出这是一棵

考虑使用树形DP。对节点 \(i\),维护从点 \(i\) 出发经过它的子树每个点至少一次并返回,最少需要走多少路。

因为最后可以停在任意一点,我们可以让小w最后走最长的那条路,然后停在最长那条路的末端。也就是说,最后的答案是节点 \(x\) 存储的距离最小值减去一条最长的,从结点 \(x\) 出发到一个叶子结点结束的路径长度。

AC 代码中出现的 \(\texttt{auto []}\)结构化绑定声明

AC 代码

作者 岛田小雅
#include <bits/stdc++.h>
using namespace std;

const int N = 5e4+2;
int n, x;
vector<pair<int,int>> e[N];
int vis[N];
long long save[N]; // 对每个结点存储经过它的子树每个点至少一次并返回的距离最小值
long long longest_distance;

void dfs(int u, long long tmp_distance)
{
    longest_distance = max(longest_distance,tmp_distance);
    if(u!=x && e[u].size()==1) return; // 不是根且入度为1,说明是叶子,没有子树,直接返回
    for(auto [v,w]:e[u])
    {
        if(!vis[v])
        {
            vis[v] = true;
            dfs(v,tmp_distance+w);
            vis[v] = false;
            save[u] += save[v]+2*w;
        }
    }
}

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> n >> x;
    for(int i = 1; i < n; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        e[u].emplace_back(v,w);
        e[v].emplace_back(u,w);
    }
    vis[x] = true;
    dfs(x,0);
    vis[x] = false;
    cout << save[x]-longest_distance << '\n';
    return 0;
}
posted @ 2022-09-26 13:10  岛田小雅  阅读(19)  评论(0编辑  收藏  举报