1021 Deepest Root (25 分)

1021 Deepest Root (25 分)

题意

给出一个无向图,如果图是联通的,以图的某个节点当作根节点则图可看作是一棵树,求你找出最使树深度最大的节点。若有多个这样的节点则从小到大输出。
图不是联通的则输出Error: K components K为图的连通块数量。

思路

可以先判断图是否连通还是有多个连通块。通过并查集实现。
若联通,则从任一点v开始遍历图,得到离v最远的节点的集合Q。再从集合Q中任一点s遍历图,得到离s点最远的节点结合W,满足要求的节点为Q与W的并集。
并查集:
用一个数组pre存贮各个节点的父节点,初始化每个节点的父节点为它本身。
查找父节点,并压缩路径。查找父节点,父节点的父节点直到每个结点的父节点等于他自己,该节点即为根节点,并把所有节点的父节点设置为根节点。该结构类似于只有两层的树,便于查找根节点。
合并两个集合。如果两个节点的根节点不同,则为两个集合p q。让另一个集合p的根节点的父节点等于q的根节点。

代码

#include<stdio.h>
#include<set>
#include<vector>
#include<stack>
#include<string.h> 
using namespace std;
set<int> s,list1,list2;
set<int>::iterator iter;
vector<int> mp[10007];
int pre[10007],xmax,cnt,vis[10007],order[10007];
int find(int x)
{
	int p,y;
	p=x;
	while(x!=pre[x]){
		x=pre[x];
	}
	while(p!=x){
		y=pre[p];
		pre[p]=x;
		p=y;
	}
	return x;
}
void link(int a,int b)
{
	pre[a]=b;
}
int Count(int n)
{
	for(int i=1;i<=n;i++){
		s.insert(find(i));
	}
	return s.size();
}
void dfs(int begin,set<int> &vt)
{
//	printf("begin=%d\n",begin);
	memset(order,0,sizeof(order));
	memset(vis,0,sizeof(vis));
	int next;
	xmax=0;
	stack<int>st;
	st.push(begin);
	vis[begin]=1;
	order[begin]=1;
	while(!st.empty()){
		next=st.top();
		if(order[next]>xmax){
			vt.clear();
//			printf("\n\n\n");
			xmax=order[next];
//			cnt=1;
//			printf("##%d\n",xmax);
			vt.insert(next);
//			printf("insert=%d\n",next);
		}else if(order[next]==xmax){
//			cnt++;
//			printf("@@%d %d %d\n",order[next],next,xmax);
			vt.insert(next);
//			printf("1insert=%d\n",next);
		}
		st.pop();
		for(int i=0;i<mp[next].size();i++){
			if(vis[mp[next][i]]!=1){
				vis[mp[next][i]]=1;
				st.push(mp[next][i]);
				order[mp[next][i]]=order[next]+1;
			}
		}
	}
}
int main()
{
	int n,p,q,count,x,y;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		pre[i]=i;
	}
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		p=find(x);
		q=find(y);
		if(q!=p){
			link(p,q);
		}
		mp[x].push_back(y);
		mp[y].push_back(x);
	}
	count=Count(n);
	if(count!=1){
		printf("Error: %d components",count);
	}else{
		dfs(1,list1);
//		for(iter=list1.begin();iter!=list1.end();++iter){
//			printf("#%d\n",*iter);
//		}
		iter=list1.begin();
//		iter;
//		printf("!!!!%d\n",*iter);
		dfs(*iter,list2);
//		printf("%d^^^\n",list2.size());
		for(iter=list2.begin();iter!=list2.end();++iter){
			list1.insert(*iter);
//			printf("%d\n",*iter);
//			printf("%d\n",*iter);
		}
//		printf("\n");
		for(iter=list1.begin();iter!=list1.end();++iter){
			printf("%d\n",*iter);
		}
	}
	
	return 0;
}

set简单用法

set可以去重并排序。
set< int >s
s.insert() 往s中加入元素
s.size() 获取s的大小(元素个数)
set< int >::iterator iter; 迭代器,通过迭代器才能得到s中的元素
for(iter=s.begin();iter!=s.end();++iter){ //遍历s中的元素
printf("%d\n",*iter);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值