牛客题解 水图
链接: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;
}