0
点赞
收藏
分享

微信扫一扫

PAT_甲级_1021 Deepest Root (25分) (C++)【DFS/连通分量/段错误/超时 #简单清晰!】


目录

​​1,题目描述​​

​​题目大意​​

​​输入​​

​​输出​​

​​2,思路​​

​​思路一​​

​​思路二​​

​​算法​​

​​段错误​​

​​3,代码​​

​​思路一​​

​​思路二​​

1,题目描述

PAT_甲级_1021 Deepest Root (25分) (C++)【DFS/连通分量/段错误/超时 #简单清晰!】_DFS连通分量

Sample Input 1:

5
1 2
1 3
1 4
2 5

Sample Output 1:

3
4
5

Sample Input 2:

5
1 3
1 4
2 5
3 4

Sample Output 2:

Error: 2 components

 

题目大意

一棵树以不同的节点作为根节点时,树可能会有不同的高度,使树的高度达到最大值时的节点为Deepest Root。

输入

第一行:节点数目N(<=10^4,编号1-N)

N-1行:描述树中每条边连接的两个节点

输出

若为非连通图,输出Error: k components ,k即连通分量数目

否则,按序号从小到大,输出所有的Deepest Root;

2,思路

思路一

野蛮解法。先判断是否为连通图,若不是连通图,则对每一个节点调用一次dfs,保留并更新Deepest Root。

结果显示这种算法会有一个测试点超时。(还有一个段错误,可能是我自己代码的问题。。。)

 

思路二

参考柳神的解题思路。

两次dfs。第一次dfs保留所有的最高高度的节点,从中选择一个节点,进行第二次dfs,同样保留所有的最高高度节点。两个节点集合的并集,就是所求内容。 (很神奇!!!)

 

算法

  • 第一次dfs算法过程中,用set<int> depth记录所有具有最高高度的节点;
  • 判断是否还有节点未被访问(有多个联通分量),是的话只需要继续dfs并输出连通分量个数即可,否则继续;
  • 将set<int> depth赋值给set<int> ans,并从ans中取一个元素(第一个就行)再次进行dfs,用set<int> depth记录所有具有最高高度的节点;
  • 将ans与depth中的内容合并(求并集)即可;

 

段错误

  • 若出现段错误,请检查在接收边的数据时,你的上限是<n还是<n-1。n的话,问题就在这里了。

 

3,代码

思路一

也把思路一的代码贴出来,有兴趣的同学可以看一下。(有一个测试点超时,还有一个段错误)

#include<iostream>
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;

bool visited[10001];
bool graph[10001][10001];
vector<int> depth;
int temDeep = 0, deepest = 0, n = 0, num = 1;

void dfs(int start, int deep){
visited[start] = true;
for(int i = 1; i <= n; i++){
if(graph[start][i] == true && visited[i] == false) dfs(i, deep+1);
}
if(deep > temDeep) temDeep = deep;
}

int main(){
//#ifdef ONLINE_JUDGE
//#else
// freopen("1.txt", "r", stdin);
//#endif


scanf("%d", &n);
for(int i = 0; i < n; i++){
int a, b;
scanf("%d%d", &a, &b);
graph[a][b] = graph[b][a] = true;
}

for(int i = 1; i <= n; i++){
fill(visited, visited + 10001, false);
temDeep = 0;
dfs(i, 0);

for(int j = 1; j <= n; j++){
if(visited[j] == false){
num += 1;
dfs(j, 0);
}
}
if(num > 1){
printf("Error: %d components", num);
return 0;
}

if(temDeep > deepest){
deepest = temDeep;
depth.clear();
depth.push_back(i);
}else if(temDeep == deepest){
depth.push_back(i);
}
}


for(int i = 0; i < depth.size(); i++){
printf("%d\n", depth[i]);
}

return 0;
}

思路二

绝对清晰易懂!

#include<iostream>
#include<set>
#include<algorithm>
using namespace std;

bool visited[10001];
bool graph[10001][10001];
set<int> ans, depth; //ans最终结果 depth暂时存放具有最高高度的节点
int temDeep = 0, n = 0, num = 1; //tempDeep临时最大高度 n节点数目 num连通分量数

void dfs(int start, int deep){
visited[start] = true;
for(int i = 1; i <= n; i++){
if(graph[start][i] == true && visited[i] == false) dfs(i, deep+1);
}
if(deep > temDeep){
temDeep = deep;
depth.clear();
depth.insert(start);
}else if(deep == temDeep){
depth.insert(start);
}
}

int main(){
scanf("%d", &n);
for(int i = 0; i < n-1; i++){ //注意是n-1(n个节点 n-1条边)!!!
int a, b;
scanf("%d%d", &a, &b);
graph[a][b] = graph[b][a] = true;
}

fill(visited, visited + 10001, false);
dfs(1, 1);
for(int j = 1; j <= n; j++){
if(visited[j] == false){
num += 1;
dfs(j, 1);
}
}
if(num > 1){ //判断连通分量数目
printf("Error: %d components", num);
return 0;
}

ans = depth; //第一次dfs中具有相同最高高度的节点 存放至答案set中
depth.clear();
fill(visited, visited + 10001, false);
temDeep = 0;
dfs(*ans.begin(), 1); //在第一次dfs中具有相同最高高度的节点中 选择一个进行第二次dfs

for(auto it = depth.begin(); it != depth.end(); it++){// it != depth.end()
ans.insert(*it); //两个集合求并集(由于是set 直接插入即可)
}
for(auto it = ans.begin(); it != ans.end(); it++){
printf("%d\n", *it);
}

return 0;
}

 

举报

相关推荐

0 条评论