在写题目前先写一些自己的感想。
之前刷题一直是自己在楞刷题,倒是也解决了很多问题,可是没有形成一套有效的模板。其实写代码这个东西还是有套路的,什么时候该快排,什么时候该深度遍历,掌握了这个套路很多问题都能迎刃而解,尤其还是PTA这种套路还比较明显的题库。
这道题自己做的时候有两个测试点一直过不去,于是决定沉下心好好看看别人的,参考了《算法笔记》和网上大神的代码,发现自己真的还很不够。
之前一直不想用C++的标准库,心高气傲觉得这些东西自己多几行代码也能实现,虽说这样说也没错,可是后来又一想,现成的轮子不用似乎还是傻了点,于是决定从这道题开始用一用C++的标准库,用了才觉得,真香~
解题分为两个步骤,先判断是否是连通图,如果是的话,再判断最长路径起点是哪些。
连通图的判断比较好理解,就是从第一个节点开始深度优先遍历,遍历过的节点都标记为已访问,一个节点遍历完成以后,寻找下一个还未被访问过的节点遍历,如果存在这样一个点,说明这个图不是连通图。
寻找最长路径起点的话,在网上学到了一个十分有效率的方法:
从任意一点出发,将其最长路径的尾节点放入一个集合中,再从集合中任意一点出发,将其最长路径尾节点也放入集合中,最后集合中的节点就是最终需要的最长路径起点(或者说是最深树的根节点)。
对于集合,set这个东西真是太好用了,自己去除重复元素还给排好序,真的是很客气的一个容器,嗯。
下面是代码:
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
int N;
vector<vector<int>> path;//采用vector构建的邻接表存储图
bool visit[10001];
int maxlength = 0;
vector<int> temp;
set<int> res;
int dfs(int root, int deep)
{
visit[root] = true;
if(deep > maxlength)
{
temp.clear();
temp.push_back(root);
maxlength = deep;
}
else if(deep == maxlength)
temp.push_back(root);
for(int i=0;i < path[root].size();i++)
{
if(visit[path[root][i]]==false)
dfs(path[root][i], deep+1);
}
return 0;
}
int main()
{
int cnt = 0;
int temps;
scanf("%d", &N);
path.resize(N+1);
for(int i=0;i<N-1;i++)
{
int tempx, tempy;
scanf("%d %d", &tempx, &tempy);
path[tempx].push_back(tempy);
path[tempy].push_back(tempx);
}
for(int i=1;i<=N;i++)
{
if(visit[i] == false)
{
dfs(i, 1);
if(i==1)
{
if(temp.size()!=0)
temps = temp[0];
for(int j=0;j<temp.size();j++)
res.insert(temp[j]);
}
cnt++;
}
}
if(cnt>1)
{
printf("Error: %d components", cnt);
return 0;
}
temp.clear();
maxlength = 0;
fill(visit, visit+10001, false);
dfs(temps, 1);
for(int i=0;i<temp.size();i++)
res.insert(temp[i]);
for(auto it=res.begin(); it != res.end(); it++)
printf("%d\n", *it);
return 0;
}