首先跑一遍DFS获取连通分支数,当只有一个连通分支时,再搜索能让树最深的根节点(主要参考《算法笔记》的做法)。
记录一下错误:
- 段错误:基本上段错误都是因为数组越界导致的,要么是数组开的不够大,要么访问了数组外的地址,本题中告诉N个结点,接下来N-1行是边的信息,如果for循环写顺手很容易写成
i=0;i<N;i++
,应该是i=0;i<N-1;i++
,当然这还是审题不清的锅。 - 按照《算法笔记》讲的思想,首先从任意节点出发dfs得到一个最深的叶结点集合A,然后从A集合中任意选一个结点出发dfs得到另一个最深的叶结点集合B,A和B的并集就是最终结果(使用set可以避免排序和去重)。一开始写成了对A集合中的每一个结点都进行了一次dfs,导致测试点3超时。
代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
vector<int> G[10005];
int vis[10005]={0};
set<int> ans;
set<int> tmp;//随便选一个结点开始深搜得到的最深的顶点
int maxdeep=-1;//记录深度
void dfs(int v,int deep){//pre防止访问回来
vis[v]=1;
for(auto w:G[v]){
if(!vis[w]){
dfs(w,deep+1);
}
}
if(deep>maxdeep){
maxdeep=deep;
tmp.clear();
tmp.insert(v);
}else if(deep==maxdeep){
tmp.insert(v);
}
}
void dfscon(int v){
vis[v]=1;
for(auto w:G[v]){
if(!vis[w]){
dfscon(w);
}
}
}
int main() {
#ifdef ONLINE_JUDGE
#else
freopen("1.txt","r",stdin);
#endif
int N;
cin >> N;
for(int i=0;i<N-1;i++){//N-1行啊!!!! 段错误!!
int v,w;
cin >> v >> w;
G[v].push_back(w);
G[w].push_back(v);
}
//先求连通分支数,若大于2都不需要接着搜了
int k=0;
for(int i=1;i<=N;i++){
if(!vis[i]){
k++;
dfscon(i);
}
}
if(k>1) cout << "Error: "<< k << " components";
else{
memset(vis,0,sizeof(vis));
dfs(1,0);//先dfs出一个临时最深的集合
for(set<int>::iterator it=tmp.begin();it!=tmp.end();it++){//将这个集合先放到ans中
ans.insert(*it);
}
memset(vis,0,sizeof(vis));
dfs(*ans.begin(),0);
for(set<int>::iterator it=tmp.begin();it!=tmp.end();it++){//再最后合并
ans.insert(*it);
}
for(set<int>::iterator it=ans.begin();it!=ans.end();it++)
cout << *it << endl;
}
return 0;
}