2024年9月GESP真题及题解(C++七级): 小杨寻宝
题目描述
小杨有一棵包含n nn个节点的树,树上的一些节点放置有宝物。
小杨可以任意选择一个节点作为起点并在树上移动,但是小杨只能经过每条边至多一次,当小杨经过一条边后,这条边就会消失。小杨每经过一个放置有宝物的节点就会取得该宝物。
小杨想请你帮他判断自己能否成功取得所有宝物。
输入格式
本题单个测试点内有多组测试数据。输入第一行包含一个正整数t tt,代表测试用例组数。
接下来是t tt组测试用例。对于每组测试用例,一共n + 1 n+1n+1行。
第一行包含一个正整数n nn,代表树的节点数。
第二行包含n nn个非负整数a 1 , a 2 , … a n a_1, a_2, \dots a_na1,a2,…an,其中如果a i = 1 a_i = 1ai=1,则节点i ii放置有宝物;若a i = 0 a_i = 0ai=0,则节点i ii没有宝物。
之后n − 1 n - 1n−1行,每行包含两个正整数x i , y i x_i, y_ixi,yi,代表存在一条连接节点x i x_ixi和y i y_iyi的边。
输出格式
对于每组测试数据,如果小杨能成功取得所有宝物,输出 Yes,否则输出 No。
输入输出样例 1
输入 1
2 5 0 1 0 1 0 1 2 1 3 3 4 3 5 5 1 1 1 1 1 1 2 1 3 3 4 3 5输出 1
Yes No说明/提示
样例 1 解释
对于第一组测试用例,小杨从节点2 22出发,按照2 − 1 − 3 − 4 2-1-3-42−1−3−4的顺序即可成功取得所有宝物。
数据规模与约定
| 子任务编号 | 数据点占比 | t tt | n nn |
|---|---|---|---|
| 1 11 | 20 % 20\%20% | ≤ 10 \leq 10≤10 | ≤ 5 \leq 5≤5 |
| 2 22 | 20 % 20\%20% | ≤ 10 \leq 10≤10 | ≤ 10 3 \leq 10^3≤103 |
| 3 33 | 60 % 60\%60% | ≤ 10 \leq 10≤10 | ≤ 10 5 \leq 10^5≤105 |
对全部的测试点,保证1 ≤ t ≤ 10 1 \leq t \leq 101≤t≤10,1 ≤ n ≤ 10 5 1 \leq n \leq 10^51≤n≤105,0 ≤ a i ≤ 1 0 \leq a_i \leq 10≤ai≤1,且保证树上至少有一个点放置有宝物。
思路分析
问题本质
这道题的核心是判断树中所有宝物节点是否在一条简单路径上。
关键理解
- 移动限制:每条边只能走一次,这意味着路径不能有分支,必须是简单路径
- 需要遍历所有宝物节点:但路径必须是线性的
- 结论:能成功取得所有宝物 ⇔ 所有宝物节点在一条简单路径上
解决方案
找到宝物节点的直径:
- 任意选择一个宝物节点作为起点
- 找到距离该节点最远的宝物节点
u - 从
u出发,找到距离u最远的宝物节点v u和v之间的路径就是宝物节点的直径
检查所有宝物节点是否在路径
u-v上:- 对于任意节点
i,如果它位于路径u-v上,则满足:dist(u,i) + dist(i,v) = dist(u,v)
- 因此只需要检查每个宝物节点是否满足这个条件
- 对于任意节点
算法步骤
- 建树(邻接表)
- 找到任意一个宝物节点作为起点
- 两次DFS求宝物节点的直径端点
u和v - 检查所有宝物节点是否在路径
u-v上
代码实现
#include<bits/stdc++.h>usingnamespacestd;constintN=1e5+10;// 最大节点数// 邻接表存储树vector<int>g[N];// a[]: 记录每个节点是否有宝物// d1[]: 记录从节点u到其他节点的距离// d2[]: 记录从节点v到其他节点的距离inta[N],d1[N],d2[N];intn;// 节点数intu,v;// 宝物节点直径的两个端点intmx;// 记录当前搜索中的最远距离/* DFS计算距离 * u 当前节点 * fa 父节点(避免回环) * dist 从起点到当前节点的距离 * d[] 距离数组,记录从起点到每个节点的距离 * * 同时更新最远的宝物节点 */voiddfs(intu,intfa,intdist,intd[]){d[u]=dist;// 记录距离// 如果当前节点有宝物,且距离比当前最远距离更大if(a[u]&&dist>mx){mx=dist;// 更新最远距离v=u;// 记录最远节点(参数v是全局变量,会被修改)}// 遍历所有邻居节点for(intx:g[u]){if(x!=fa){// 避免回到父节点dfs(x,u,dist+1,d);}}}//solve函数:处理单个测试用例voidsolve(){cin>>n;// 初始化:清空邻接表,读取宝物信息for(inti=1;i<=n;i++){cin>>a[i];g[i].clear();}// 建立树的邻接表for(inti=1;i<n;i++){intx,y;cin>>x>>y;g[x].push_back(y);g[y].push_back(x);}// 找到第一个宝物节点作为起点ints=1;while(s<=n&&!a[s])s++;// 题目保证至少有一个宝物节点,所以s一定存在// 第一步:从s出发,找到最远的宝物节点umx=-1;// 初始化最远距离dfs(s,0,0,d1);// 计算从s到所有节点的距离u=v;// v现在是最远的宝物节点// 第二步:从u出发,找到最远的宝物节点v// 此时u-v的路径就是宝物节点的直径mx=-1;dfs(u,0,0,d1);// 重新计算从u到所有节点的距离,记录在d1中intt=v;// v现在是另一个端点,暂存为t// 第三步:从t出发,计算到所有节点的距离,记录在d2中dfs(t,0,0,d2);// 检查所有宝物节点是否在u-t路径上for(inti=1;i<=n;i++){if(a[i]){// 只检查宝物节点// 判断节点i是否在路径u-t上:// 如果dist(u,i) + dist(i,t) == dist(u,t),则i在u-t路径上if(d1[i]+d2[i]!=d1[t]){cout<<"No\n";return;}}}cout<<"Yes\n";}intmain(){// 优化输入输出ios::sync_with_stdio(false);cin.tie(0);intT;// 测试用例组数cin>>T;while(T--){solve();}return0;}功能分析
核心算法:树直径法判断共线性
- 第一次DFS:从任意宝物节点找到最远的宝物节点
u - 第二次DFS:从
u找到最远的宝物节点v,确定宝物节点的直径 - 第三次DFS:计算所有节点到
v的距离 - 验证:检查每个宝物节点是否在
u-v路径上
关键性质
如果所有宝物节点在一条简单路径上,那么这条路径一定是宝物节点形成的"子图"的直径
对于树上的三个点
u, i, v,点i在u-v路径上当且仅当:dist(u,i) + dist(i,v) = dist(u,v)
时间复杂度
- 每次DFS: O(n)
- 三次DFS: O(3n) = O(n)
- 总复杂度: O(t*n),其中t≤10,n≤10 5 10^5105
空间复杂度
- 邻接表: O(n)
- 距离数组: O(n)
- 总复杂度: O(n)
各种学习资料,助力大家一站式学习和提升!!!
#include<bits/stdc++.h>usingnamespacestd;intmain(){cout<<"########## 一站式掌握信奥赛知识! ##########";cout<<"############# 冲刺信奥赛拿奖! #############";cout<<"###### 课程购买后永久学习,不受限制! ######";return0;}1、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html
2、csp信奥赛冲刺一等奖有效刷题题解:
CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
3、GESP C++考级真题题解:
GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转
GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转
GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html
4、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转
· 文末祝福 ·
#include<bits/stdc++.h>usingnamespacestd;intmain(){cout<<"跟着王老师一起学习信奥赛C++";cout<<" 成就更好的自己! ";cout<<" csp信奥赛一等奖属于你! ";return0;}