视频讲解:[GESP202503 六级] 树上漫步-信息学奥赛GESP等级考试真题解析
一、原题
题目描述
小 A 有一棵 n 个结点的树,这些结点依次以 1,2,⋯,n 标号。
小 A 想在这棵树上漫步。具体来说,小 A 会从树上的某个结点出发,每一步可以移动到与当前结点相邻的结点,并且小 A 只会在偶数步(可以是零步)后结束漫步。
现在小 A 想知道,对于树上的每个结点,从这个结点出发开始漫步,经过偶数步能结束漫步的结点有多少个(可以经过重复的节点)。
输入格式
第一行,一个正整数 n。
接下来 n−1 行,每行两个整数 ui,vi,表示树上有⼀条连接结点 ui 和结点 vi 的边。
输出格式
一行,n 个整数。第 i 个整数表示从结点 i 出发开始漫步,能结束漫步的结点数量。
输入输出样例
输入 #1
3 1 3 2 3输出 #1
2 2 1输入 #2
4 1 3 3 2 4 3输出 #2
3 3 1 3说明/提示
对于 40% 的测试点,保证 1≤n≤10^3。
对于所有测试点,保证 1≤n≤2×10^5。
二、做题思路
1)填充数据
#include<bits/stdc++.h> using namespace std; map<int,vector<int>>g; int main(){ //1)填充数据 //1.1)确定节点数量n int n;cin>>n; //1.2)填充n-1条边的链接情况 for(int i=1;i<=n-1;i++){ int u,v;cin>>u>>v; g[u].push_back(v); g[v].push_back(u); } return 0; }2)深搜:计算奇/偶数高度的节点数量
#include<bits/stdc++.h> using namespace std; map<int,vector<int>>g; bool vis[200005]; int d[200005]; int total[2]; //2.2)深搜每个结点 void dfs(int x,int deep){ //2.4)计算奇数偶数结点数量 total[deep%2]++; //2.5)标记当前结点的高度 d[x]=deep; vis[x]=1; for(auto it:g[x]){ if(vis[it]==0){ //2.3)计算当前结点高度 dfs(it,deep+1); } } } int main(){ //1)填充数据 //... //2)深搜:计算奇/偶数高度的节点数量 //2.1)从结点1开始深搜 dfs(1,1); return 0; }3)输出结果
#include<bits/stdc++.h> using namespace std; map<int,vector<int>>g; bool vis[200005]; int d[200005]; int total[2]; //2.2)深搜每个结点 void dfs(int x,int deep){ //2.4)计算奇数偶数结点数量 //.... //2.5)标记当前结点的高度 //... //2.3)计算当前结点高度 //... } int main(){ //1)填充数据 //... //2)深搜:计算奇/偶数高度的节点数量 //2.1)从结点1开始深搜 dfs(1,1); //3)输出结果 for(int i=1;i<=n;i++){ //结点高度是奇数,输出奇数总数 if(d[i]%2==1) cout<<total[1]<<" "; //结点高度是偶数,输出奇数偶数 else cout<<total[0]<<" "; } return 0; }三、答案
#include<bits/stdc++.h> using namespace std; map<int,vector<int>>g; bool vis[200005]; int d[200005]; int total[2]; //2.2)深搜每个结点 void dfs(int x,int deep){ //2.4)计算奇数偶数结点数量 total[deep%2]++; //2.5)标记当前结点的高度 d[x]=deep; vis[x]=1; for(auto it:g[x]){ if(vis[it]==0){ //2.3)计算当前结点高度 dfs(it,deep+1); } } } int main(){ //1)填充数据 //1.1)确定节点数量n int n;cin>>n; //1.2)填充n-1条边的链接情况 for(int i=1;i<=n-1;i++){ int u,v;cin>>u>>v; g[u].push_back(v); g[v].push_back(u); } //2)深搜:计算奇/偶数高度的节点数量 //2.1)从结点1开始深搜 dfs(1,1); //3)输出结果 for(int i=1;i<=n;i++){ //结点高度是奇数,输出奇数总数 if(d[i]%2==1) cout<<total[1]<<" "; //结点高度是偶数,输出奇数偶数 else cout<<total[0]<<" "; } return 0; }