[GESP202512 六级] 路径覆盖

视频讲解:GESP202512 六级 路径覆盖-信息学奥赛GESP等级考试真题解析

一、原题

题目描述

给定一棵有 n 结点的有根树 T,结点依次以 1,2,...,n 编号,根结点编号为 1。方便起见,编号为 i 的结点称为结点 i。

初始时 T 中的结点均为白色。你需要将 T 中的若干个结点染为黑色,使得所有叶子到根的路径上至少有一个黑色结点。将结点 i 染为黑色需要代价 ci​,你需要在满足以上条件的情况下,最小化染色代价之和。

叶子是指 T 中没有子结点的结点。

输入格式

第一行,一个正整数 n,表示结点数量。

第二行,n−1 个正整数 f2​,f3​,...,fn​,其中 fi​ 表示结点 i 的父结点的编号,保证 fi​<i。

第三行,n 个正整数 c1​,c2​,...,cn​,其中 ci​ 表示将结点 i 染为黑色所需的代价。

输出格式

一行,一个整数,表示在满足所有叶子到根的路径上至少有一个黑色结点的前提下,染色代价之和的最小值。

输入输出样例

输入 #1

复制代码
4
1 2 3
5 6 2 3

输出 #1

复制代码
2

输入 #2

复制代码
7
1 1 2 2 3 3
64 16 15 4 3 2 1

输出 #2

复制代码
10

说明/提示

对于 40% 的测试点,保证 2≤n≤16。

对于另外 20% 的测试点,保证 fi​=i−1。

对于所有测试点,保证 2≤n≤10^5,1≤ci​≤10^9。

二、做题思路

1)邻接表构造树

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
long long c[100005];
int main(){
	//1)邻接表构造树
	//1.1)确定结点数量n
	int n;cin>>n; 
	//1.2)填充2-n结点的父亲结点
	for(int i=2;i<=n;i++){
		int f;cin>>f;
		g[f].push_back(i);
	}
	//1.3)确定n个结点代价 
	for(int i=1;i<=n;i++) cin>>c[i];
	return 0; 
} 

2)深搜

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
long long c[100005];
void dfs(int x){
	//2.2)深搜每个子结点
	for(auto it:g[x]){
		dfs(it);
	}
}
int main(){
	//1)邻接表构造树
	//...
	//2)深搜
	//2.1)从根节点1开始搜 
	dfs(1); 
	return 0; 
} 

3)计算每个结点的最小代价

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
long long c[100005];
void dfs(int x){
	//3)计算每个结点的最小代价
	//3.0)叶子结点跳过
	if(g[x].size()==0) return ; 
	//3.1)计算所有子结点总和
	long long sum=0; 
	//2.2)深搜每个子结点
	for(auto it:g[x]){
		dfs(it);
		sum+=c[it];
	}
	//3.2)所有子结点  和 当前结点 取最小值
	c[x]= min(sum,c[x]);
}
int main(){
	//1)邻接表构造树
	//...
	//2)深搜
	//2.1)从根节点1开始搜 
	dfs(1); 
	//3.3)输出根节点代价
	cout<<c[1]; 
	return 0; 
} 

三、答案

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
map<int,vector<int>>g;
long long c[100005];
void dfs(int x){
	//3)计算每个结点的最小代价
	//3.0)叶子结点跳过
	if(g[x].size()==0) return ; 
	//3.1)计算所有子结点总和
	long long sum=0; 
	//2.2)深搜每个子结点
	for(auto it:g[x]){
		dfs(it);
		sum+=c[it];
	}
	//3.2)所有子结点  和 当前结点 取最小值
	c[x]= min(sum,c[x]);
}
int main(){
	//1)邻接表构造树
	//1.1)确定结点数量n
	int n;cin>>n; 
	//1.2)填充2-n结点的父亲结点
	for(int i=2;i<=n;i++){
		int f;cin>>f;
		g[f].push_back(i);
	}
	//1.3)确定n个结点代价 
	for(int i=1;i<=n;i++) cin>>c[i];
	//2)深搜
	//2.1)从根节点1开始搜
	dfs(1);
	//4)输出根节点代价
	cout<<c[1]; 
	return 0; 
} 
相关推荐
INGNIGHT1 小时前
1861 · 老鼠跳跃(坐标型dp)
数据结构·c++
Lazionr1 小时前
手撕 unordered_set 和 unordered_map,剖析哈希表底层实现
c++·算法
0+1112 小时前
算法 --归并排序
数据结构·算法·排序算法
Run_Teenage2 小时前
算法:树的重心、树的直径
算法
专注仿真2 小时前
高代价计算后置:探测、交战、毁伤三条链路的统一设计哲学
算法·探测·毁伤
xie0510_2 小时前
Any类简要实现
开发语言·c++·算法
字节跳动的猫2 小时前
LikeShop 种草社区模块二开:笔记发布、话题广场与商品挂载实现
数据结构·数据库
在所不辞兄2 小时前
为什么PINN非常适合求解有限元模型
人工智能·深度学习·神经网络·算法·机器学习
一棵树73512 小时前
数据结构闲聊
数据结构·算法