视频讲解:GESP202509 六级 货物运输-信息学奥赛GESP等级考试真题解析
一、原题
题目描述
A 国有 n 座城市,依次以 1,2,...,n 编号,其中 1 号城市为首都。这 n 座城市由 n−1 条双向道路连接,第 i 条道路(1≤i<n)连接编号为 ui,vi 的两座城市,道路长度为 li。任意两座城市间均可通过双向道路到达。
现在 A 国需要从首都向各个城市运送货物。具体来说,满载货物的车队会从首都开出,经过一座城市时将对应的货物送出,因此车队需要经过所有城市。A 国希望你设计一条路线,在从首都出发经过所有城市的前提下,最小化经过的道路长度总和。注意一座城市可以经过多次,车队最后可以不返回首都。
输入格式
第一行,一个正整数 n,表示 A 国的城市数量。
接下来 n−1 行,每行三个正整数 ui,vi,li,表示一条双向道路连接编号为 ui,vi 的两座城市,道路长度为 li。
输出格式
一行,一个整数,表示你设计的路线所经过的道路长度总和。
输入输出样例
输入 #1
4
1 2 6
1 3 1
3 4 5
输出 #1
18
输入 #2
7
1 2 1
2 3 1
3 4 1
7 6 1
6 5 1
5 1 1
输出 #2
9
说明/提示
对于 30% 的测试点,保证 1≤n≤8。
对于另外 30% 的测试点,保证仅与一条双向道路连接的城市恰有两座。
对于所有测试点,保证 1≤n≤10^5,1≤ui,vi≤n,1≤li≤10^9。
二、做题思路
1)填充数据

cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
int to,l;
};
map<int,vector<node>>g;
int main(){
//1)填充数据
//1.1)确定结点数量
int n;cin>>n;
//1.2)填充每条道路信息
for(int i=1;i<=n-1;i++){
int u,v,l;cin>>u>>v>>l;
g[u].push_back({v,l});
g[v].push_back({u,l});
}
return 0;
}
2)深搜

cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
int to,l;
};
map<int,vector<node>>g;
bool vis[100005];
//2.2)深搜每个结点
void dfs(int x,long long now){
vis[x]=1;
for(auto it:g[x]){
if(vis[it.to]==0){
dfs(it.to,now+it.l);
}
}
}
int main(){
//1)填充数据
//...
//2)深搜
//2.1)从结点1开始
dfs(1,0);
return 0;
}
3)计算每条路径的权重,找最大

cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
int to,l;
};
map<int,vector<node>>g;
bool vis[100005];
long long maxx=LLONG_MIN;
//2.2)深搜每个结点
void dfs(int x,long long now){
//3)计算每条路径的权重,找最大
//叶子结点,证明到最底下了
//只链接1个结点,且访问
if(g[x].size()==1&&vis[g[x][0].to]==1){
maxx=max(now,maxx);
return ;
}
vis[x]=1;
for(auto it:g[x]){
if(vis[it.to]==0){
dfs(it.to,now+it.l);
}
}
}
int main(){
//1)填充数据
//...
//2)深搜
//2.1)从结点1开始
dfs(1,0);
return 0;
}
4)计算总长

cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
int to,l;
};
map<int,vector<node>>g;
bool vis[100005];
long long maxx=LLONG_MIN;
long long total=0;
//2.2)深搜每个结点
void dfs(int x,long long now){
vis[x]=1;
//3)计算每条路径的权重,找最大
//...
for(auto it:g[x]){
if(vis[it.to]==0){
dfs(it.to,now+it.l);
//4)计算总长
total+=it.l;
}
}
}
int main(){
//1)填充数据
//...
//2)深搜
//2.1)从结点1开始
dfs(1,0);
return 0;
}
5)最优解:(总长-最大)*2+最大
cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
int to,l;
};
map<int,vector<node>>g;
bool vis[100005];
long long maxx=LLONG_MIN;
long long total=0;
//2.2)深搜每个结点
void dfs(int x,long long now){
vis[x]=1;
//3)计算每条路径的权重,找最大
//...
//4)计算总长
//...
}
int main(){
//1)填充数据
//...
//2)深搜
//...
//5)最优解:(总长-最大)*2+最大
cout<<(total-maxx)*2+maxx;
return 0;
}
三、答案
cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
int to,l;
};
map<int,vector<node>>g;
bool vis[100005];
long long maxx=LLONG_MIN;
long long total=0;
//2.2)深搜每个结点
void dfs(int x,long long now){
vis[x]=1;
//3)计算每条路径的权重,找最大
//叶子结点,证明到最底下了
//只链接1个结点,且访问
if(g[x].size()==1&&vis[g[x][0].to]==1){
maxx=max(now,maxx);
return ;
}
for(auto it:g[x]){
if(vis[it.to]==0){
dfs(it.to,now+it.l);
//4)计算总长
total+=it.l;
}
}
}
int main(){
//1)填充数据
//1.1)确定结点数量
int n;cin>>n;
//1.2)填充每条道路信息
for(int i=1;i<=n-1;i++){
int u,v,l;cin>>u>>v>>l;
g[u].push_back({v,l});
g[v].push_back({u,l});
}
//2)深搜
//2.1)从结点1开始
dfs(1,0);
//5)最优解:(总长-最大)*2+最大
cout<<(total-maxx)*2+maxx;
return 0;
}