PAT A 1021.Deepest Root (25)

题目

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、在深度最大的叶节点中任取其中一个作为新的根(代码中取了第一个),重新计算各节点深度,将深度最大的叶节点暂存。

31,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;
}


 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值