题意分析:
(1)这一题型比较巧妙,直接给出一个树的拓扑结构,求出这棵树最深的根,言外之意就是指:当以这个节点为根的时候,树具有最深的深度。若这个图具有多个连通分支,就输入分支数。
(2)首先给出算法,随后证明这个算法一定能找到它所有的最深根:第一步:从任意一个节点开始进行深度优先遍历,找到离他最远的节点(可能不止一个,记为集合A);第二步:再从A中任意选一个节点出发进行深度优先遍历,找到离他最远的节点(记为集合B),最后最深根就是这两个集合的并集。
证明:第一步找出的节点一定是全局的最深根。
1根据全局最优解一定是局部最优解的原理:最后全局的最深根一定也是某个局部最优解,比如:因为全局最深的根是固定的,不失一般性,我们就把他们标为1、2、3、4、5,那么从图中中任意一点出发,例如A,从他出发找到的局部最优解一定是在1、2、3、4、5,反之,如不在,也就是说有比1、2、3、4、5更深的节点,我们假设它存在并且成为B,那么可想而知,从1到B肯定要比从1到2要深,这就与1、2、3、4、5是全局最优解矛盾,所以假设不成立。原命题成立。即局部最优解一定在1、2、3、4、5中。
2由第一步知道局部最优解是固定的,且全局最优解是局部最优解,根据这两条结论,得出:第一次遍历得到的最深的节点就是最深根
由于从最深根出发到最深的叶子节点是相互对称的,所以我们再从当前的最深根出发遍历一次得到其他的最深根,然后做一次去重即可。
(3)也可以不去重,在第二次遍历的时候直接通过层序遍历算出每个节点所在的层数存到数组中,最后再遍历一次
可能坑点:
(1)第一次遍历结束后要记得将最大深度重置为0,所有节点访问标记置为0.
#include <iostream>
#include <string.h>
#include <vector>
#include <map>
#include <queue>
using namespace std;
bool visit[10001]={0};
int level[10001]={0};
bool root[10001]={0};
int maxLength=0;
map<int,vector<int> > tree;
queue<int >qu;
void getDeepest(int start)
{
qu.push(start);
level[start]=1;
visit[start]=1;
while(!qu.empty())
{
int temp=qu.front();
if(tree[temp].size()==0)
{
maxLength=level[temp];
break;
}
vector<int>::iterator ite = tree[temp].begin();
qu.pop();
for(;ite!=tree[temp].end();ite++)
{
if(!visit[*ite])
{
qu.push(*ite);
visit[*ite]=1;
level[*ite]=level[temp]+1;
if(level[*ite]>maxLength)maxLength=level[*ite];
}
}
}
}
int main()
{
int N;
cin>>N;
int i=1,from,to;
int cnt=1;
while(i<N)
{
cin>>from>>to;
if(visit[from]&&visit[to])cnt++;
visit[from]=1;
visit[to]=1;
tree[from].push_back(to);
tree[to].push_back(from);
i++;
}
if(cnt>1)cout<<"Error: "<<cnt<<" components"<<endl;
else
{
memset(visit,0,sizeof(visit));
getDeepest(1);
int first;
for(int i=1;i<=N;i++)
{
if(level[i]==maxLength)
{
root[i]=1;
first=i;
}
}
memset(visit,0,sizeof(visit));
maxLength=0;
getDeepest(first);
for(int i=1;i<=N;i++)
{
if(level[i]==maxLength)
{
root[i]=1;
}
}
for(int i=1;i<=N;i++)
{
if(root[i])cout<<i<<endl;
}
}
return 0;
}