上饶市网站建设_网站建设公司_导航易用性_seo优化
2026/1/8 21:32:49 网站建设 项目流程

​欢迎大家订阅我的专栏:算法题解:C++与Python实现!
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!

专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。

适合人群:

  • 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
  • 希望系统学习C++/Python编程的初学者
  • 想要提升算法与编程能力的编程爱好者

附上汇总贴:USACO历年白银组真题解析 | 汇总-CSDN博客


【题目来源】

洛谷:[P10135 USACO24JAN] Potion Farming S - 洛谷

【题目描述】

你正在玩你最喜欢的手机游戏。在尝试收集药水,以便有机会击败传说中的牛头怪boss。游戏地图是一系列标有1…N的房间,这些房间由N-1条边连接形成一棵树( 2 ≤ N ≤ 10 5 ) (2\le N\le 10^5)(2N105)

你可以通过进行一系列的“遍历”来探索地图。一次遍历是从房间1到树中任何其他房间的一条简单路径。一次遍历结束后,你可以从房间1开始另一次遍历。一旦地图的每个房间至少被遍历过一次,地图就算完成。你的主要目标是用最少的遍历次数完成地图。 你的次要目标是尽可能多地收集药水。在一次遍历开始前,一瓶药水会在地图上的某个房间生成。通过在当前遍历中生成药水的房间你就可以捡起它。如果你没有捡起药水,那么它将在当前遍历结束后消失,所以你不能在未来的遍历中捡起它。 作为一个聪明的程序员,在查看游戏文件后,你能够在接下来的N次遍历之前找出药水将出现在哪里。如果你在最少的遍历次数内完成地图,你可以从地图上收集到的最大数量的药水是多少?

【输入】

输入的第一行包含一个整数N,表示地图中房间的数量。 然后是N个空格分隔的整数p 1 p 2 … p N p_1p_2\dots p_Np1p2pN,其中1 ≤ p i ≤ N 1\le p_i\le N1piNp i p_ipi表示在第i次遍历之前药水会出现在哪个房间。

最后,接着是N-1行,每行有两个用空格分隔的整数*a b ( 1 ≤ a , b ≤ N ) a b(1\le a,b\le N)ab(1a,bN)*,代表房间a和b之间的一条边。可以保证这些边组成了一棵树。

【输出】

输出一行包含一个整数,即你可以在最少遍历次数的情况下从地图中获得的最大药水量。

【输入样例】

5 5 4 3 2 1 1 2 1 3 3 4 3 5

【输出样例】

2

【算法标签】

《洛谷 P10135 Potion Farming》 #USACO# #2024#

【代码详解】

#include<bits/stdc++.h>usingnamespacestd;constintN=100005;intn,p[N],leaf[N],d[N];// leaf[x] -- 以 x 为根的子树中的叶子节点数量// d[x] -- 以 x 为根的子树最多能获得的药水数量vector<int>e[N];// 邻接表存储树// 深度优先搜索计算每个子树的叶子节点数量voiddfs(intx,intfa){// 如果 x 不是根节点且是叶子节点(度为1),则 leaf[x] = 1if(x!=1&&e[x].size()==1){leaf[x]=1;}// 遍历所有子节点for(inti=0;i<e[x].size();i++){inty=e[x][i];if(y==fa)continue;// 避免回溯父节点dfs(y,x);leaf[x]+=leaf[y];// 累加子树的叶子数量}}// 计算每个子树最多能获得的药水数量voidcalc(intx,intfa){// 遍历所有子节点for(inti=0;i<e[x].size();i++){inty=e[x][i];if(y==fa)continue;// 避免回溯父节点calc(y,x);d[x]+=d[y];// 累加子树的药水数量}d[x]=min(d[x],leaf[x]);// 药水数量不超过叶子数量}intmain(){scanf("%d",&n);// 输入节点数量// 输入每个节点的优先级 p[i]for(inti=1;i<=n;i++){scanf("%d",&p[i]);}// 构建树的邻接表for(inti=1;i<n;i++){inta,b;scanf("%d%d",&a,&b);e[a].push_back(b);e[b].push_back(a);}dfs(1,0);// 从根节点开始计算叶子数量// 根据优先级分配初始药水(前 leaf[1] 个优先级最高的节点获得 1 药水)for(inti=1;i<=leaf[1];i++){d[p[i]]++;}calc(1,0);// 从根节点开始计算最大药水数量printf("%d\n",d[1]);// 输出根节点能获得的最大药水数量return0;}

【运行结果】

5 5 4 3 2 1 1 2 1 3 3 4 3 5 2

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询