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);
}