[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; 
} 
相关推荐
维克兜率天5 分钟前
【维克】指数调整:哪些股票会被“强制买入“?
人工智能·python·算法
罗西的思考43 分钟前
【轻量化复刻大模型】线性注意力交互式演示
人工智能·算法·机器学习
神也畏惧菠萝1 小时前
Day08 Python流程控制从入门到上瘾:if/match/while/for四件套,从B站登录一路打到猜数字游戏
python·算法·数据存储·for·while·if·ifelse
揽星河..1 小时前
【C语言】分支和循环
c语言·c++·算法
丘山望岳2 小时前
单调栈和单调队列
数据结构
Fuyo_11193 小时前
C++ AVL树保姆级详解:从平衡因子到四大旋转机制
java·c++·算法
jktantan3 小时前
每个节点 41 字节:把一棵百万节点树拆进 14 个 typed array
前端·javascript·vue.js·算法·typescript
揽星河..3 小时前
【C语言】猜数字游戏
c语言·算法·游戏
LabVIEW开发4 小时前
CTM-3 红外测温仪 + LabVIEW 温度怎么测?
算法·labview·测试·labview程序