题目
A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=10000) which is the number of nodes, and hence the nodes are numbered from 1 to N. Then N-1 lines follow, each describes an edge by given the two adjacent nodes' numbers.
Output Specification:
For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print "Error: K components" where K is the number of connected components in the graph.
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
即在图有多个连通域时求连通域数,否则求可以使深度达到最深的根。
(由于限制了边的数目n-1,如果图不能构成树,必然有多个组成部分)
如果暴力方法求每个点为根时的深度,代价为n^2,基本会超时。
取某个点为根后能获得最大深度,
即以该点为根,从根到最深的叶的路线是原先图中距离最远的两个点之间的路线。
则在任取一个点作为根后,符合要求的点必然为如下两种情况之一:
1、为两个深度最深的叶节点。
2、一个为最深的叶节点,另一个为所有最深叶点公共树枝段上的另一分支上的最深节点。
步骤
1、任取一个节点(代码中取了第一个),获取深度,暂存所有深度最大的叶节点。
2、在深度最大的叶节点中任取其中一个作为新的根(代码中取了第一个),重新计算各节点深度,将深度最大的叶节点暂存。
3、1,2中获取的所有节点的并集即为所有符合要求的节点。
代码:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int MAX=0x37777777;
vector<int> map[10005]; //每个对应编号的点所连通的点
int deep[10005]; //每个节点作为叶节点时所能取得的最大深度
int flag[10005]; //计算每个节点为根时的各个点的深度的临时数据
int n; //节点数量
struct deep_node //探测用
{
int n; //点的编号
int deep; //点的深度
};
int DK(int node); //探测n个点map中,node作为根时的深度,多个组成部分时返回组成部分数的负数
int Deep(int node); //探测n个点map中,node作为根时的深度
int main()
{
int i,node1,node2;
int temp,max_deep=0; //临时数据,记录最大深度,编号为[]点为根时的深度
int to_test; //即随机选择的一个符合要求的点
cin>>n;
for(i=1;i<n;i++) //输入数据
{
deep[i]=0;
scanf("%d %d",&node1,&node2);
if(node1!=node2)
{
map[node1].push_back(node2); //在内部按1~n对点编号
map[node2].push_back(node1);
}
}
temp=DK(1); //!!!先随机取一点为根,计算深度,(此处取1)
if(temp<0)
{
cout<<"Error: "<<-temp<<" components";
return 0;
}
for(i=1;i<=n;i++)
{
if(flag[i]==temp)
{
to_test=i; //!!!随机取一个深度最深的节点(如果只有1个点则为根)
break;
}
}
for(;i<=n;i++) //!!!将所有深度最深的节点标记,这些点必然是
{
if(flag[i]==temp)
deep[i]=MAX;
}
temp=DK(to_test); //!!!探测随机取的那个点,同时刷新deep[]数据
deep[to_test]=temp;
if(temp>max_deep)
max_deep=temp;
for(i=1;i<=n;i++) //!!!输出之前标记的点和第二次探测时的最深叶节点
{
if(deep[i]>=max_deep)
printf("%d\n",i);
}
return 0;
}
int DK(int node)
{
deep_node n1,n2; //临时点
int mdeep=1; //最大深度
int k=1; //组成部分
int i,j;
for(i=1;i<=n;i++)
flag[i]=0;
mdeep=Deep(node);
for(i=1;i<=n;i++)
{
if(flag[i]==0)
{
Deep(i);
k++;
}
}
if(k>1)
return -k;
else
return mdeep;
}
int Deep(int node)
{
deep_node n1,n2; //临时点
int mdeep=1; //最大深度
int k=1; //组成部分
int i,j;
queue<deep_node> deep_test; //深度探测序列
n1.deep=1; //初始化,压入根节点n
n1.n=node;
flag[node]=1;
deep_test.push(n1);
while(!deep_test.empty())
{
n1=deep_test.front();
deep_test.pop();
if(n1.deep>mdeep) //刷新深度
mdeep=n1.deep;
if(!map[n1.n].empty()) //有路
{
for(i=0;i<map[n1.n].size();i++)
{
if(flag[map[n1.n][i]]==0) //通向的点没有探测过
{
n2.n=map[n1.n][i];
n2.deep=n1.deep+1;
flag[n2.n]=n2.deep;
if(n2.deep>deep[n2.n]) //!!!特殊处理,如果节点深度大于之前的计算值,会刷新
deep[n2.n]=n2.deep;
deep_test.push(n2);
}
}
}
}
return mdeep;
}