题目:http://pat.zju.edu.cn/contests/pat-a-practise/1021
题意:N个节点,给出N-1条边。要求判断是否为树,若不为树,输出有几个连通分量;若为树,输出符合条件的树根,即以该节点为跟能够得到最大树深。
思路:先用并查集判断是否为树,不为树则根据f [ i ]==i 得到连通分量数; 若为树,则任意从一个节点开始深度搜索,找到此时深度最大的节点maxpoint,此时的maxpoint即为符合题意的根节点之一。然后从maxpoint进行第二次深度搜索,得到深度最大的节点均可作为符合题意的根节点。
N==1时要特判。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
vector<int> map[10001];
int f[10001],maxpoint,maxdep;
bool vis[10001];
struct cmpp
{
bool operator()(int x,int y)
{
return x>y;
}
};
priority_queue<int,vector<int>,cmpp> q;
int find(int a)
{
if(f[a]==a) return a;
return find(f[a]);
}
void Union(int a,int b)
{
f[b]=find(a);
}
void dfs(int node,int dep)
{
vis[node]=false;
if(dep==maxdep) q.push(node);
if(dep>maxdep)
{
while(!q.empty())
{
q.pop();
}
q.push(node);
maxdep=dep;
maxpoint=node;
}
int len=map[node].size(),i;
for(i=0;i<len;i++)
if(vis[map[node][i]])
dfs(map[node][i],dep+1);
}
int main()
{
int n,i,a,b;
scanf("%d",&n);
if(n==1)
{
printf("1\n");return 0;
}
for(i=1;i<=n;i++)
f[i]=i;
for(i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
Union(a,b);
map[a].push_back(b);
map[b].push_back(a);
}
int count=0;
for(i=1;i<=n;i++)
if(f[i]==i) count++;
if(count>1) printf("Error: %d components\n",count);
else
{
while(!q.empty())
q.pop();
maxdep=0;
maxpoint=1;
memset(vis,true,sizeof(vis));
dfs(1,0);
memset(vis,true,sizeof(vis));
int tmp=maxpoint;
dfs(maxpoint,0);
q.push(tmp); //别忘加入根节点!!!
while(!q.empty())
{
printf("%d\n",q.top());
q.pop();
}
}
return 0;
}