[GESP202509 六级] 货物运输(含视频)

视频讲解: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; 
}
相关推荐
余额瞒着我当琳3 小时前
C++算法学习篇5--二分查找法
c++·学习·算法
起个名字费劲死了3 小时前
基于灰度/形状的2D模板匹配
算法
杜 硕3 小时前
归并排序详解
数据结构·算法·排序算法
科技观察哨3 小时前
国产纳米定位平台与精密位移台量产能力图谱(2026):Z轴压电、XYθZ、六自由度并联与光刻/检测/装配选型指南
网络·人工智能·算法
鶴哥只手遮天4 小时前
《OpenFOAM 源码深度剖析》系列-第 3 章 字典系统、IO 体系与对象注册表
算法·开源
鶴哥只手遮天4 小时前
《OpenFOAM 源码深度剖析》系列-第 2 章 wmake:OpenFOAM 自研构建系统与编译配置体系
算法·开源
用户81849100742164 小时前
我把工位上的“AI牛马”养成了:一个技术人的 AiPy 实战手记
算法
Tisfy4 小时前
LeetCode 3727.最大交替平方和:排序 (双指针可选)
算法·leetcode·题解·贪心·数组·排序
鶴哥只手遮天4 小时前
《OpenFOAM 源码深度剖析》系列-第 9 章 有限体积离散框架:`fvMatrix`、`fvSchemes` 与 `fvSolution`
算法·开源