首页 > 试题广场 >

Deepest Root (25)

[编程题]Deepest Root (25)
  • 热度指数:3016 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
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 .

输入描述:
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.


输出描述:
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.
示例1

输入

5<br/>1 2<br/>1 3<br/>1 4<br/>2 5

输出

3<br/>4<br/>5
来自博客http://blog.csdn.net/sinat_29278271
    一道很有意思的题目,顺带让我回忆了一下高中的有机化学,然而你一定不知道为什么这会和高中有机化学扯上关系。
    先说一下题目大意,给你一个无向无环图,希望你找出其中的最长路,这道题最快只用两次DFS就够了,我用的是一个比较笨的方法,找到每个叶节点然后dfs求最长路并记录,最后将所有最长路为最大值的节点输出,在PAT上也能过,但是在牛客网上是过不了的(牛客网数据略强)。
    判断图是否连接用并查集解决,我觉得我不用多说的。然后图连通时,第一遍任取起点DFS用vis数组记录每个节点的在dfs搜索中的距离,与dfs能达到的最大距离Max,将所有vis[i]==Max的i插入set。第二遍从Set中任取一个元素,重复第一次遍历时的操作。然后输出set中的所有元素。
先上代码,后发证明。
# include <cstdio>
# include <iostream>
# include <cstring>
# include <algorithm>
# include <set>
# include <vector>
using namespace std;
const int size  = 10000; 
const int debug = 1;
class DisjointSet
{
private:
    int *T,size,sum;
    int FindRoot(int i){return T[i] < 0 ? i : (T[i] = FindRoot(T[i]));}
public:
    DisjointSet(int _size):size(_size)
    {
        T = new int[size];
        Init();
    }
    void Init(){sum = size;memset(T,-1,sizeof(int)*size);}
    bool Unioned(int i,int j){return FindRoot(i)==FindRoot(j);}
    void Union(int i,int j)
      {
        if ( (i = FindRoot(i) ) != ( j = FindRoot(j) ) )
        {
            T[i] = T[i] + T[j];
            T[j] = i;
            sum--;
        }
      }
    int FindSum(int i){return -T[FindRoot(i)];}
    int SumOfUnits(){return sum;}
    ~DisjointSet(){delete[] T;}
};
vector<int> v[size];
int vis[size];
void dfs(int i,int dist,int &MAX)
{
     vis[i] = dist;
     MAX = max(MAX,vis[i]);
     for (int k=0;k<v[i].size();k++)
         if (vis[v[i][k]]==-1)   
		    dfs(v[i][k],dist+1,MAX);
}
int main()
{
  int i,j,temp;
  int n;
  scanf("%d",&n);
  DisjointSet ds(n); 
  for (i=0;i<n-1;i++)
    {
      int a,b;
      scanf("%d%d",&a,&b);a--,b--;
      v[a].push_back(b);
      v[b].push_back(a);
      ds.Union(a,b);
    }
  if (ds.SumOfUnits() == 1)
    {
  	  int start,Max;
  	  set<int> s;
      for (Max=start=i=0;i<2;i++)
        {
       	  memset(vis,-1,sizeof(vis));
		  dfs(start,0,Max);
		  for (j=0;j<n;j++)
		      if (vis[j]==Max)
				  s.insert(j);
		  start = *s.begin();
		}
      for (set<int>::iterator it = s.begin();it!=s.end();it++)
	      printf("%d\n",(*it)+1);     
    }
  else 
      printf("Error: %d components\n",ds.SumOfUnits());
  return 0;
}
     
 这个算法有一个很玄奥的地方,就是两次遍历都有帅气逼人地用到了任取一词,为了说明算法的正确性,让我先上一张图
就是上面这幅图,圆的是顶点,长的是边,中间蓝色加省略号是省略省略不提的部分,然后红色是主干,也就是最长路,绿色是侧枝。
很容易理解对于任何一条侧枝 DE,存在|DE| < min(|AD|,|DC|),现在分类讨论,
      1.对于第一次DFS选择的起点,如果是红色路径上的点,第一次DFS得到的最长路必定是距离较远的最长路顶点,在这幅图中就是说要么是A,要么是C,同时可以看到,假如起点是B,我们在DFS的时候E点的DFS深度也会是最长路径,也就是说我们选出了最起码一侧的所有最长路的端点。
      2.如果第一次选择的起点是侧枝上的点,如F (侧枝上还有侧枝的情况请自行脑补) ,F在进行DFS搜索的时候必定会经过D点,那么问题已经转化成了第一题的问题。
至于第二次DFS应该很好理解既然第一次选出了一端的所有顶点,第二次肯定会选出另一端所有顶点。
     至此该问题圆满解决。

编辑于 2015-08-30 02:10:33 回复(5)

从任意一个节点开始进行深度优先遍历,找到离他最远的节点(可能不止一个,记为集合A);第二步:再从A中任意选一个节点出发进行深度优先遍历,找到离他最远的节点(记为集合B),最后最深根就是这两个集合的并集。

证明:第一步找出的节点一定是全局的最深根。

1     根据全局最优解一定是局部最优解的原理:最后全局的最深根一定也是某个局部最优解,比如:因为全局最深的根是固定的,不失一般性,我们就把他们标为1、2、3、4、5,那么从图中中任意一点出发,例如A,从他出发找到的局部最优解一定是在1、2、3、4、5,反之,如不在,也就是说有比1、2、3、4、5更深的节点,我们假设它存在并且成为B,那么可想而知,从1到B肯定要比从1到2要深,这就与1、2、3、4、5是全局最优解矛盾,所以假设不成立。原命题成立。即局部最优解一定在1、2、3、4、5中。

2    由第一步知道局部最优解是固定的,且全局最优解是局部最优解,根据这两条结论,得出:第一次遍历得到的最深的节点就是最深根

由于从最深根出发到最深的叶子节点是相互对称的,所以我们再从当前的最深根出发遍历一次得到其他的最深根,然后做一次去重即可。
package go.jacob.day1017;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

/**
 * 1021. Deepest Root (25)
 * 
 * @author Jacob 一共N个点,有N-1条边。只要components大于1,必定有环。
 *         寻找最远距离的时候,只要使用两次DFS就可以了。原因如下: 树中最远的距离必是距离根节点R最远和次远的两个叶节点的连线。
 *         可以任意选择一个节点,进行深度优先搜索,第一次找到最远的节点。 用刚刚找到的最远节点为根节点做dfs,再次寻找最远节点(可能有多个)
 */
public class Demo1 {
    static int components = 0;
    static int n;
    static ArrayList<Integer>[] matrix;
    static boolean[] visited;
    static int[] deep;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        matrix = new ArrayList[n + 1];
        for (int i = 1; i < n + 1; i++) {
            matrix[i] = new ArrayList<Integer>();
        }
        visited = new boolean[n + 1];
        deep = new int[n + 1];
        for (int i = 0; i < n - 1; i++) {
            int a = sc.nextInt(), b = sc.nextInt();
            matrix[a].add(b);
            matrix[b].add(a);
        }
        for (int i = 1; i < n + 1; i++) {
            if (!visited[i]) {
                dfs(i, i);
                components++;
            }
        }
        if (components == 1) {// 说明输入正常
            Queue<Integer> queue = new LinkedList<Integer>();
            ArrayList<Integer> list = new ArrayList<Integer>();
            queue.add(1);
            initVisited(visited);
            visited[1] = true;
            int max = getDeep(queue, 1);
            // 找到最远节点,加入到list中
            for (int i = 1; i < n + 1; i++){
                if (deep[i] == max){
                    list.add(i);
                }
            }
            initVisited(visited);
            max = list.get(0);
            visited[max] = true;
            queue.add(max);
            max = getDeep(queue, max);
            for (int i = 1; i < n + 1; i++){
                if (deep[i] == max && !list.contains(i)){
                    list.add(i);
                }
            }
            Collections.sort(list);
            for (Integer v : list)
                System.out.println(v);

        } else {
            System.out.println("Error: " + components + " components");
        }
        sc.close();
    }

    /*
     * 获得当前树的最深深度
     */
    private static int getDeep(Queue<Integer> queue, int end) {
        int level = 1;
        int tmpEnd=end;
        while (!queue.isEmpty()) {
            int tmp = queue.poll();
            for (Integer v : matrix[tmp]) {
                if (!visited[v]) {
                    deep[v] = level;
                    queue.offer(v);
                    visited[v] = true;
                    tmpEnd=v;
                }
            }
            if (!queue.isEmpty()&&tmp == end) {
                end = tmpEnd;
                level++;
            }
        }
        return level-1;
    }

    /*
     * 初始化visited矩阵(设置为false)
     */
    private static void initVisited(boolean[] visited2) {
        for (int i = 1; i < n + 1; i++)
            visited[i] = false;
    }

    /*
     * 深度优先搜索
     */
    private static void dfs(int root, int pre) {
        visited[root] = true;
        for (Integer temp : matrix[root]) {
            if (temp.equals(pre))
                continue;
            if (!visited[temp])
                dfs(temp, root);
        }
    }
}

发表于 2017-10-17 17:00:02 回复(3)
PAT上勉强算是一遍AC吧(测试点1一个小坑,即N==1的特殊情况,其他测试点一遍过)
牛客上数据略强,测试点7超时,其他都可以
用的递归DFS,思路很简单,先DFS判断是否连通
若连通,则不难证明:
(1)满足要求的点必然只有一个邻接点
(2)连通图中必然没有环
DFS所有邻接点数目为1的点,求其最大值即可

#include <cstdio>
#include <vector>
#include <string.h>
using namespace std;
const int MAXN=1e4+10;

int n;
vector<int> vex[MAXN];
bool visited[MAXN]={false},vis[MAXN];
int dfs(int root,int depth){
    int d,maxd=depth;
    vis[root]=true;
    for(int i=0;i<vex[root].size();++i)
        if(!vis[vex[root][i]]){
            d=dfs(vex[root][i],depth+1);
            if(maxd<d) maxd=d;
        }
    return maxd;
}
void dfs2(int root){
    visited[root]=true;
    for(int i=0;i<vex[root].size();++i)
        if(!visited[vex[root][i]]) dfs2(vex[root][i]);
}
int main()
{
    int a,b;
    scanf("%d",&n);
    if(n==1){printf("1");return 0;}
    for(int i=1;i<n;++i){
        scanf("%d%d",&a,&b);
        vex[a].push_back(b);
        vex[b].push_back(a);
    }
    int cnt=0,depth,maxdepth=-1;
    vector<int> MaxDVex;
    for(int i=1;i<=n;++i)
        if(!visited[i]){
            dfs2(i);
            ++cnt;
        }
    if(cnt>1) printf("Error: %d components",cnt);
    else{
        for(int i=1;i<=n;++i){
            memset(vis,0,sizeof(vis));
            if(!vis[i] && vex[i].size()==1){
                ++cnt;
                depth=dfs(i,1);
                if(maxdepth<depth){
                    maxdepth=depth;
                    MaxDVex.clear();
                    MaxDVex.push_back(i);
                }else if(maxdepth==depth)
                    MaxDVex.push_back(i);
            }
        }
        for(int i=0;i<MaxDVex.size();++i)
            printf("%d\n",MaxDVex[i]);
    }
    return 0;
}
发表于 2018-08-11 17:01:39 回复(1)
牛客网超时,pat一个测试用例非通过,求解答。
我的思路:用并查集求联通集,然后用dfs求出深度
#include<stdio.h>

#include<string>

#include<iostream>

#include<vector>

#include<map>

#include<algorithm>

using namespace std;


int findRoot2(int *tree,int i)

{

    if(tree[i]==-1)return i;

    else

    {

        int tmp = findRoot2(tree,tree[i]);

        tree[i]=tmp;

        return tmp;

    }

}

int maxlevel =0;



void dfs(vector<int> *result,int level,int startNode,bool *already)

{

    //if(result[startNode].size()<=0) return;

    already[startNode] = true;

    if(maxlevel<level)

    {

        maxlevel = level;

    }

    for(int i=0;i<result[startNode].size();i++)

    {

        if(!already[result[startNode][i]])

        {

            int current = level+1;

            dfs(result,current,result[startNode][i],already);

        }

    }

}


int main()

{

    int N;

    

    scanf("%d",&N);

    

    int *tree = new int[N+1];

    vector<int> *result = new vector<int>[N+1];

    for(int i=1;i<=N;i++)

    {

        tree[i]=-1;

    }

    if(N==1)

    {

        int a,b;

        scanf("%d %d",&a,&b);

        cout<<a<<endl;

        return 0;

    }

    for(int i=1;i<=N-1;i++)

    {

        int a,b;

        scanf("%d %d",&a,&b);

        result[a].push_back(b);

        result[b].push_back(a);

        a=findRoot2(tree,a);

        b=findRoot2(tree,b);

        if(a!=b)

        {

            tree[a]=b;

        }

        }

    int sum=0;

    for(int j=1;j<=N;j++)

    {

        if(tree[j]==-1)

            sum++;

    }

    map<int,vector<int>> deep;

        bool *already = new bool[N+1];

    if(sum>1)

    {

        cout<<"Error: "<<sum<<" components"<<endl;

        return 0 ;

    }

    else

    {

        

        //寻找最大的深度的root id

        for(int i=1;i<=N;i++)

        {

            //深度遍历叶结点

            if(result[i].size()==1)

            {

                maxlevel = 1;

                for(int k=1;k<=N;k++)

                {

                    already[k]=false;

                }

                already[i]=true;

                dfs(result,0,i,already);

                deep[maxlevel].push_back(i);

                

            }

        }

    }

    int max=0;

    for(map<int,vector<int>>::iterator it=deep.begin();it!=deep.end();it++)

    {

        if(it->first>max)

        {

            max=it->first;

        }

    }


    sort(deep[max].begin(),deep[max].end());

    for(int i=0;i<deep[max].size();i++)

    {

        cout<<deep[max][i]<<endl;

    }

    return 0;

}

发表于 2018-02-28 14:46:10 回复(0)
//方法1(此方法在数据量大时会超时)
#include <iostream>                      
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=10010;
vector<int> Adj[maxn],ans;
bool vis[maxn]={false};
int n,v1,v2,temp,block,deepest=0;
void DFS(int u,int depth){
    vis[u]=true;
    if(depth>temp) temp=depth;           //temp为当前点i为根时的最大深度
    for(int i=0;i<Adj[u].size();i++){
        int v=Adj[u][i];
        if(vis[v]==false)
            DFS(v,depth+1);
    }
}
void DFSTrave(int root){
    DFS(root,1);                        //从当前点i(传入为root)开始遍历
    block++;
    for(int u=1;u<=n;u++){
        if(vis[u]==false){
            DFS(u,1);
            block++;
        }
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n-1;i++){
        scanf("%d%d",&v1,&v2);
        Adj[v1].push_back(v2);
        Adj[v2].push_back(v1);
    }
    for(int i=1;i<=n;i++){
        temp=0;
        block=0;
        fill(vis,vis+maxn,false);
        DFSTrave(i);                   //每次从不同点开始遍历
        if(block==1){                  //n个点n-1条边的连通图必为树
            if(temp==deepest) ans.push_back(i); //本次遍历得到的树深度与最大深度相同
            else if(temp>deepest){
                deepest=temp;
                ans.clear();
                ans.push_back(i);
            }
        }
        else{                          //若图不连通
            printf("Error: %d components\n",block);
            break;
        }
    }
    if(ans.size()!=0){
        sort(ans.begin(),ans.end());
        for(int i=0;i<ans.size();i++)
            cout<<ans[i]<<endl;
    }
    return 0;
}


//方法2 //全局最优解是局部最优解,第一次遍历得到的最深的结点就是最深根 //由于从最深根出发到最深的叶子节点是相互对称的,所以我们再从当前的最深根出发遍历一次得到其他的最深根,再去重。  #include <iostream>                       
#include <vector>                        
#include <algorithm>
#include <set>
using namespace std;
const int maxn=10010;
vector<int> Adj[maxn],temp,ans;
set<int> s;                               //用set不用排序,不用去重
bool vis[maxn]={false};
int n,v1,v2,block=0,deepest=0;
void DFS(int u,int depth){
    vis[u]=true;
    if(depth==deepest) ans.push_back(u);
    else if(depth>deepest){               //若当前深度比最大树高大
        deepest=depth;
        ans.clear();
        ans.push_back(u);
    }
    for(int i=0;i<Adj[u].size();i++){
        int v=Adj[u][i];
        if(vis[v]==false)
            DFS(v,depth+1);
    }
}
void DFSTrave(int root){
    DFS(root,1);                         //从当前点i(传入为root)开始遍历
    block++;
    for(int u=1;u<=n;u++){
        if(vis[u]==false){
            DFS(u,1);
            block++;
        }        
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n-1;i++){
        scanf("%d%d",&v1,&v2);
        Adj[v1].push_back(v2);
        Adj[v2].push_back(v1);
    }
    DFSTrave(1);                        //先从点1开始一次遍历
    if(block==1){                       //n个点n-1条边的连通图必为树
        temp=ans;                       //让temp先保存第一次遍历时离根最远的结点集合
        ans.clear();
        fill(vis,vis+maxn,false);
        DFSTrave(temp[0]);              //从任意一个第一次遍历所得的最远结点开始第二次遍历
    }
    else {                              //若图不连通
        printf("Error: %d components\n",block);
        return 0;
    }
    for(int i=0;i<temp.size();i++)      //将两次遍历所得的结点插入set中(自动去重并排序)
        s.insert(temp[i]);
    for(int i=0;i<ans.size();i++)
        s.insert(ans[i]);
    for(auto i=s.begin();i!=s.end();i++)
        cout<<*i<<endl;
    return 0;
} 

编辑于 2019-01-29 23:40:02 回复(0)
土办法!
DFS ***底。
DFS 求连通分量 求深度
pta AC 牛客有个 超时。有时间回来改成 并查集 求连通分量就好了。

// 1021_Deepest_Root.cpp: 定义控制台应用程序的入口点。
//



#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//----------定义图
struct vexNode {  vector<int> Edge;
};
vector<vexNode> G;

int cnt; //结点计数
bool *visit;// 访问数组
int *h;// 每个结点为根的 高度数组
int highest=0;//最高用于比较

void Dfs(int s,int h,int&hest) {  if (visit[s] == true) { return; }  visit[s] = true;  if (h > hest) {// DFS 求最大深度  hest = h;  }  for (int i = 0; i < G[s].Edge.size(); i++) {  if (visit[G[s].Edge[i]] == false) {  Dfs(G[s].Edge[i],h+1,hest);  }  }
}
int DFSTravle(int s, int &high) {// 在对整张图dfs 的过程中求连通分量。  int components = 0;// 联通分量  if (visit[s] == false) {// 先从起始点开始一次dfs  Dfs(s, 1, high); components++;  }  int t = 0;  for (int i = 1; i <= cnt; i++)// 在对整张图dfs 求得连通分量  {  if (visit[i] == false) {  Dfs(i, 1, t); components++;  }  }  return components;
}
int main()
{  cin >> cnt;  for (int i = 0; i <=cnt; i++) {  G.push_back(vexNode());  }  for (int i = 0; i < cnt-1; i++) {  int f, t;  cin >> f >> t;  G[f].Edge.push_back(t);  G[t].Edge.push_back(f);  }  visit = new bool[cnt+1];    h = new int[cnt+1];  for (int i = 1; i <=cnt; i++) { h[i] = 0; }  for (int i = 1; i <=cnt; i++) {// 对没个结点都做一次DFS  for (int j = 1; j <=cnt; j++) {  visit[j] = false;  }  int comp = DFSTravle(i,h[i]);//  得到连通分量和 对应节点的最高的深度  if (comp!= 1) {  //多个连通分liang  cout << "Error: " << comp << " components";  return 0;  }  }  vector<int> high;  int best = -1;  for (int i = 1; i <= cnt; i++) {//  选出最大深度的结点(多个 )  if (h[i] >= best) {  if (h[i] > best) {  high.clear();  }  high.push_back(i);  best = h[i];  }  }  vector<int>::iterator it = high.begin();  for (; it != high.end(); it++) {  cout << *it << endl;  }
    return 0;
} 

编辑于 2019-01-05 21:53:39 回复(0)
//两次dfs就能确定所有的最深结点
#include <cstdio>
#include <vector>
#include <cstring>
#include <set>
using namespace std;
const int maxn = 10000 + 10;

vector<int> graph[maxn];
int fa[maxn], visited[maxn] = {0};
int height[maxn] = {0}, max_height = 0;
set<int> out_node;

void init(int num){
    for(int k=1; k<=num; k++)
        fa[k] = k;
}

int find_fa(int x){ 
    while(x != fa[x])
        x = fa[x];
    return x;
}

void Union(int x, int y){
    x = find_fa(x);
    y = find_fa(y);
    if(x != y) fa[x] = y;
}

int Components_num(int num){ 
    set<int> s;
    for(int i=1; i<=num; i++){
        int set_id = find_fa(i);
        if(s.count(set_id) == 0)
            s.insert(set_id);
    }
    return s.size();
}

void Dfs(int s){
    visited[s] = 1;
    for(unsigned int i=0; i<graph[s].size(); i++){
        int v = graph[s][i];
        if(visited[v]) continue;
        height[v] = height[s] + 1;
        max_height = (max_height > height[v]) ? max_height : height[v];
        Dfs(v);
    }
}

int main(){
    int n;
    scanf("%d", &n);
    init(n);
    for(int i=0; i<n-1; i++){
        int u, v;
        scanf("%d %d", &u, &v);
        graph[u].push_back(v);
        graph[v].push_back(u);
        Union(u, v);
    }
    int cnm = Components_num(n);
    if(cnm > 1) 
        printf("Error: %d components\n", cnm);
    else{
        height[1] = 0;
        Dfs(1);
        for(int i=1; i<=n; i++){
            if(height[i] == max_height)
                out_node.insert(i);
        }
        max_height = 0;
        memset(height, 0, sizeof(height));
        memset(visited, 0, sizeof(visited));
        int s = *(out_node.begin());
        Dfs(s);
        for(int i=1; i<=n; i++){
            if(height[i] == max_height)
                out_node.insert(i);
        }
        for(auto iter=out_node.begin(); iter!=out_node.end(); iter++)
            printf("%d\n", *iter);
    }
    return 0;
}

发表于 2017-09-10 21:19:56 回复(0)
maxn要取的大一点,不然有段错误,我也是醉了,郁闷半天。。。。。
#include <cstdio>

#include <iostream>

#include <algorithm>

#include <cstring>

#include <vector>

#include <set>

using namespace std;


const int maxn=10005;

vector<int> map[maxn]; //邻接表

//**************并查集计算连通图个数****************//

int father[maxn];

//*****************初始化并查集*****************//

void init(int n){

    for (int i=0; i < n; ++i) {

        father[i] = i;

    }

}

//********************查找根节点*******************//

int getfather(int x){

    if (x != father[x]) {

        father[x] = getfather(father[x]);

    }

    return father[x];

}

//*********合并两个元素所在的集合,返回是否有环*********//

void Union(int x,int y){

    x = getfather(x);

    y = getfather(y);

    if (x != y) {

        father[x] = y;

    }

}

//*****************并查集结束****************//

//*************DFS**************//


vector<int> visited;

int deepest;

set<int> res;


void DFS(int i,int distance){

    if (distance > deepest) {

        res.clear();

        res.insert(i);

        deepest = distance;

    }

    else if (distance == deepest){

        res.insert(i);

    }

    visited[i] = 1;

    for (int j=0; j < map[i].size(); ++j) {

        if (!visited[map[i][j]]) {

            visited[map[i][j]] = 1;

            DFS(map[i][j],distance+1);

            visited[map[i][j]] = 0;

        }

    }

    visited[i] = 0;

}


int main(){

    int N,from,to;

    cin >> N;

    init(N);    //初始化并查集

    for (int i=1; i < N; ++i) {

        cin >> from >> to;

        Union(from,to);

        map[from].push_back(to);

        map[to].push_back(from);

    }

    int Sum_huan = 0;   //连通分量的个数

    for (int i=1; i < N; ++i) {

        if (father[i]==i) {

            Sum_huan++;

        }

    }

    visited.resize(N+1, 0);

    if (Sum_huan > 1) {

        cout << "Error: " << Sum_huan << " components" <<endl;

        return 0;

    }

    set<int> trees;

    //****************随便找个点1开始第一次深度搜索找到最远的点*****************//

    DFS(1, 1);

    //******************第一次找到的点一定是最后需要的那个根节点之一*************//

    for (auto it = res.begin(); it != res.end(); ++it) {

        trees.insert(*it);

    }

    //****************从最远的点开始第二次搜索******************//

    int point = (*res.begin());

    DFS(point, 1);

    for (auto it = res.begin(); it != res.end(); ++it) {

        trees.insert(*it);

    }

    for (auto it = trees.begin(); it != trees.end(); ++it) {

        cout << *it << endl;

    }

    return 0;

}


发表于 2016-09-02 09:42:16 回复(2)
#include<bits/stdc++.h>
using namespace std;

const int Max=10010;
int father[Max];
int height[Max];
int n;
vector<int> G[Max],tmp,ans;

void Initial() {
	for(int i=1; i<=n; i++) {
		father[i]=i;
		height[i]=1;
	}
}

int Find(int x) {
	if(x!=father[x]) {
		father[x]=Find(father[x]);
	}
	return father[x];
}

void Union(int x,int y) {
	x=Find(x);
	y=Find(y);
	if(x!=y) {
		if(height[x]>height[y]) {
			father[y]=x;
		} else if(height[x]<height[y]) {
			father[x]=y;
		} else {
			father[x]=y;
			height[y]++;
		}
	}
}

int Maxh=0;
void DFS(int id,int h,int f) {
	if(h>Maxh) {
		tmp.clear();
		tmp.emplace_back(id);
		Maxh=h;
	} else if(h==Maxh) {
		tmp.emplace_back(id);
	}
	for(int i=0; i<G[id].size(); i++) {
		if(G[id][i]==f) continue;
		DFS(G[id][i],h+1,id);
	}
}

int main() {
	int a,b;
	scanf("%d",&n);
	Initial();
	for(int i=1; i<n; i++) {
		scanf("%d %d",&a,&b);
		G[a].emplace_back(b);
		G[b].emplace_back(a);
		Union(a,b);
	}
	int count=0;
	for(int i=1; i<=n; i++) {
		if(i==Find(i)) {
			count++;
		}
	}
	if(count>1) {
		printf("Error: %d component\n",count);
		return 0;
	} else {
		DFS(1,1,-1);
		ans=tmp;
		DFS(ans[0],1,-1);
		for(int i=0; i<tmp.size(); i++) {
			ans.emplace_back(tmp[i]);
		}
		sort(ans.begin(),ans.end());
		printf("%d\n",ans[0]);
		for(int i=1; i<ans.size(); i++) {
			if(ans[i]!=ans[i-1])
				printf("%d\n",ans[i]);
		}
	}
	return 0;
}

发表于 2022-11-28 11:42:38 回复(0)
刚刚做完就有了新思路。这题其实可以用bfs的,从其中一点向外扩散辣~
我用的是dfs,有丶丶累。
这个代码把注释去了一个样例超时,加上注释另一个样例答案错误~。
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<bits/stdc++.h>

#define INF 2147483647
#define MIN INF+1
#define ll long long

using namespace std;

int N;
vector<int> nodes[10005];
int visit[10005];
int max_depth = MIN;
set<int> q;

int father[10005];

int find(int n) {
	while(father[n] != n) {
		n = father[n];
	}
	return n;
}

void _union(int a, int b) {
	int aa = find(a);
	int bb = find(b);
	father[aa] = father[bb];
}

void dfs(int n, int depth) {
	// if(q.count(n)) {
	// 	return;
	// }
	bool isleaf = true;
	for(auto i:nodes[n]) {
		if(visit[i] == 0) {
			visit[i] = 1;
			dfs(i, depth + 1);
			visit[i] = 0;
			isleaf = false;
		}
	}
	if(isleaf) {
		if(depth > max_depth) {
			max_depth = depth;
			q.clear();
			q.insert(n);
		} else if(depth == max_depth) {
			q.insert(n);
		}
	}
}

int main() {    
	std::ios::sync_with_stdio(false);
    std::cin.tie(0);

	cin >> N;
	
	for(int i = 0; i < N; i++) {
		visit[i] = 0;
		father[i] = i;
	}
	
	for(int i = 0; i < N - 1; i++) {
		int a, b;
		cin >> a >> b;
		a -= 1;
		b -= 1;
		nodes[a].push_back(b);
		nodes[b].push_back(a);
		_union(a,b);
	} 
	
	set<int> s;
	
	for(int i = 0; i < N; i++) {
		if(i == father[i])
			s.insert(father[i]);
	}
	
	if(s.size() > 1) {
		cout << "Error: " << s.size() << " components" << endl;
		return 0;
	}
	
	for(int i = 0; i < N; i++) {
		visit[i] = 1;
		dfs(i, 0);
		visit[i] = 0;
	}
	
	for(auto x:q) {
		cout << x + 1 << endl;	// 下标开始位置不同罢了 
	}
	
	return 0;
} 
超时代码:
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<bits/stdc++.h>

#define INF 2147483647
#define MIN INF+1
#define ll long long

using namespace std;

int N;
vector<int> nodes[10005];
int visit[10005];
int max_depth = MIN;
set<int> q;
map<int, bool> has; 

int father[10005];

int find(int n) {
	while(father[n] != n) {
		n = father[n];
	}
	return n;
}

void _union(int a, int b) {
	int aa = find(a);
	int bb = find(b);
	father[aa] = father[bb];
}

void dfs(int n, int depth) {
	// if(q.count(n)) {
	// 	return;
	// }
	// if(has.find(n) != has.end())
	// 	return;
	bool isleaf = true;
	for(auto i:nodes[n]) {
		if(visit[i] == 0) {
			visit[i] = 1;
			dfs(i, depth + 1);
			visit[i] = 0;
			isleaf = false;
		}
	}
	if(isleaf) {
		if(depth > max_depth) {
			max_depth = depth;
			// q.clear();
			// q.insert(n);
			has.clear();
			has[n] = true;
		} else if(depth == max_depth) {
			// q.insert(n);
			has[n] = true;
		}
	}
}

int main() {    
	std::ios::sync_with_stdio(false);
    std::cin.tie(0);

	cin >> N;
	
	for(int i = 0; i < N; i++) {
		visit[i] = 0;
		father[i] = i;
	}
	
	for(int i = 0; i < N - 1; i++) {
		int a, b;
		cin >> a >> b;
		a -= 1;
		b -= 1;
		nodes[a].push_back(b);
		nodes[b].push_back(a);
		_union(a,b);
	} 
	
	set<int> s;
	
	for(int i = 0; i < N; i++) {
		if(i == father[i])
			s.insert(father[i]);
	}
	
	if(s.size() > 1) {
		cout << "Error: " << s.size() << " components" << endl;
		return 0;
	}
	
	for(int i = 0; i < N; i++) {
		visit[i] = 1;
		dfs(i, 0);
		visit[i] = 0;
	}
	
	for(map<int,bool>::iterator i = has.begin(); i != has.end(); i++) {
		cout << i->first + 1 << endl;
	}
	
	return 0;
} 

edit: 噫 好了 我过了!
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<bits/stdc++.h>

#define INF 2147483647
#define MIN INF+1
#define ll long long

using namespace std;

int N;
vector<int> nodes[10005];
int visit[10005];
int max_depth = MIN;
set<int> q;
map<int, bool> has; 

int father[10005];

int find(int n) {
	while(father[n] != n) {
		n = father[n];
	}
	return n;
}

void _union(int a, int b) {
	int aa = find(a);
	int bb = find(b);
	father[aa] = father[bb];
}

void dfs(int n, int depth, int start) {
	// if(q.count(n)) {
	// 	return;
	// }
	// if(has.find(n) != has.end())
	// 	return;
	bool isleaf = true;
	for(auto i:nodes[n]) {
		if(visit[i] == 0) {
			visit[i] = 1;
			dfs(i, depth + 1, start);
			visit[i] = 0;
			isleaf = false;
		}
	}
	if(isleaf) {
		if(depth > max_depth) {
			max_depth = depth;
			// q.clear();
			// q.insert(n);
			has.clear();
			has[start] = true;
		} else if(depth == max_depth) {
			// q.insert(n);
			has[start] = true;
		}
	}
}

int main() {    
	std::ios::sync_with_stdio(false);
    std::cin.tie(0);

	cin >> N;
	
	for(int i = 0; i < N; i++) {
		visit[i] = 0;
		father[i] = i;
	}
	
	for(int i = 0; i < N - 1; i++) {
		int a, b;
		cin >> a >> b;
		a -= 1;
		b -= 1;
		nodes[a].push_back(b);
		nodes[b].push_back(a);
		_union(a,b);
	} 
	
	set<int> s;
	
	for(int i = 0; i < N; i++) {
		if(i == father[i])
			s.insert(father[i]);
	}
	
	if(s.size() > 1) {
		cout << "Error: " << s.size() << " components" << endl;
		return 0;
	}
	
	for(int i = 0; i < N; i++) {
		if(visit[i] == 0 && nodes[i].size() == 1) {
			visit[i] = 1;
			dfs(i, 0, i);
			visit[i] = 0;
		}
	}
	
	for(map<int,bool>::iterator i = has.begin(); i != has.end(); i++) {
		cout << i->first + 1 << endl;
	}
	
	return 0;
} 



编辑于 2020-09-18 19:29:19 回复(0)
pta上那个用例不是超时就是超限,救救py吧
发表于 2020-03-02 13:48:40 回复(0)
判断是否合法和找出最深节点都可以用dfs解决。
1.是否全部连通:搜一次看看每个点是否都踩到。
2.是否无环:搜的时候如果搜到已经visit过的点,如果这个点不是父节点,则有环。
3.找最深节点:对每个点dfs搜一下记录最大值,注意要记录每个点的每条边下去最深有多深,如果搜的时候发现已经有答案就直接使用答案。

代码如下,比较乱,随便看看。
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
#define dbg(x) cout << #x ": " << x << endl
using namespace std;
int N;
vector<vector<int>> G;
vector<vector<int>> deeps;
vector<int> degrees;
bool is_acyclic = true;
unordered_set<int> visited;

int dfs(int x, int from){
    visited.insert(x);
    int n = G[x].size();
    const vector<int>& g = G[x];
    int max_deep = 0;
    for(int i = 0; i < n; i++){
        if(visited.count(g[i]) == 0){
            int deep;
            if(~deeps[x][i]){
                deep = deeps[x][i];
            }
            else{
                deep = dfs(g[i], x);
            }
            if(deep > max_deep){
                max_deep = deep;
            }
            deeps[x][i] = deep;
        }
        else if(g[i] != from){
            // dbg(x);
            // dbg(from);
            // dbg(g[i]);
            is_acyclic = false;
        }
    }
    return max_deep + 1;
}

int main(){
    // ios::sync_with_stdio(false);
    cin >> N;
    G.resize(N);
    // dbg(G.size());
    deeps.resize(N);
    // dbg(deeps.size());
    degrees.resize(N);
    // dbg(degrees.size());
    for(int i = 0; i < N - 1; i++){
        int p, q;
        cin >> p >> q;
        p--, q--;
        G[p].push_back(q);
        deeps[p].push_back(-1);
        G[q].push_back(p);
        deeps[q].push_back(-1);
        degrees[p]++;
        degrees[q]++;
    }
    // dbg("here");
    vector<int> ans;
    int max_deep = 0, parts = 0;
    bool ok = true;
    for(int i = 0; i < N; i++){
        // dbg("iter");
        // dbg(i);
        if(visited.count(i) == 0){
            dfs(i, -1);
            parts++;
            if((int)visited.size() != N || !is_acyclic){
                // dbg(visited.size());
                // dbg(is_acyclic);
                ok = false;
            }
        }
        if(i && ok){
            break;
        }
    }
    for(int i = 0; i < N; i++){
        if(true || degrees[i] <= 1){
            visited.clear();
            int deep = dfs(i, -1);
            if(deep > max_deep){
                max_deep = deep;
                ans.clear();
                ans.push_back(i);
            }
            else if(deep == max_deep){
                ans.push_back(i);
            }
        }
    }
    if(!ok){
        cout << "Error: " << parts << " components" << endl;
    }
    else{
        sort(ans.begin(), ans.end());
        for(auto x : ans){
            cout << x + 1 << endl;
        }
    }
}



发表于 2019-08-28 12:55:08 回复(0)
#include<stdio.h>
#include<vector>
#include<set>
#include<string.h>
using namespace std;
vector<int>adj[10010];
int father[10010];
int N;
bool vis[10010],isroot[10010];
int findfather(int x){
    while(x!=father[x])x=father[x];
    return x;
}
void Union(int a,int b){
    int faA=findfather(a);
    int faB=findfather(b);
    if(faA!=faB)father[faB]=faA;
}

int maxdepth=0;
set<int>s,temp;
void dfs(int depth,int u){
    vis[u]=true;
    if(depth>maxdepth){
        maxdepth=depth;
        temp.clear();
        temp.insert(u);
    }
    else if(depth==maxdepth)temp.insert(u);
    for(int i=0;i<adj[u].size();i++){
        int v=adj[u][i];
        if(vis[v]==false)dfs(depth+1,v);
    }
}
int main(){
    scanf("%d",&N);
    if(N==1){
        printf("1");
        return 0;
    }
    for(int i=1;i<=N;i++)father[i]=i;
    for(int i=0;i<N-1;i++){
        int u,v;
        scanf("%d %d",&u,&v);
        adj[u].push_back(v);
        adj[v].push_back(u);
        Union(u,v);
    }
    memset(isroot,false,sizeof(isroot));
    int cnt=0;
    for(int i=1;i<=N;i++){
        if(father[i]==i)cnt++; //根的个数就是并查集的个数
    }
    if(cnt>=2){
        printf("Error: %d components\n",cnt);
        return 0;
    }
//  int block=calBlocks();
//  printf("block=%d",block);
//  return 0;
    int root;
    for(int i=1;i<=N;i++){
        if(father[i]==i)root=i;
    }
    memset(vis,false,sizeof(vis));
    dfs(0,root);//得到结点
    s=temp;
    temp.clear();
    memset(vis,false,sizeof(vis));
    dfs(0,*s.begin());
    for(auto it=temp.begin();it!=temp.end();it++)s.insert(*it);
    for(auto it=s.begin();it!=s.end();it++)printf("%d\n",*it);
    return 0;
}
发表于 2019-07-28 21:33:21 回复(0)
起初有两个error的输出点树  components计数报错。看了下别人代码后发现,bfs遍历处理的结点是从1到N。
也就是说,有结点在输入边的时候没有输入进去,仍然需要处理。
//bfs宽度优先 
#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<set>

using namespace std;

int main()
{     set<int> node_set;     map<int, set<int> > edge_map;     queue<int> node_queue;     int count = 0;//树的数量      int pre[10001] = {0};     int pre2[10001] = {0};          int N = 0;     cin>>N;          for (int i = 0; i < N-1; i++)     {         int a,b;         scanf("%d %d",&a,&b);
//        if (node_set.find(a) == node_set.end())
//            node_set.insert(a);
//        if (node_set.find(b) == node_set.end())
//            node_set.insert(b);         node_set.insert(i+1);                          edge_map[a].insert(b);         edge_map[b].insert(a);     }          node_set.insert(N);          bool is_tree = true;     int node_front;     int level = -1;     set<int> final_level;     while (!node_set.empty())      {         count ++;         int node = *node_set.begin();         node_queue.push(node);         node_queue.push(level);         final_level.insert(node);                          while(!node_queue.empty()){             node_front = node_queue.front();                          if (node_front < 0) {                 level --;                 node_queue.pop();                 if (!node_queue.empty()){                     final_level.clear();                     node_queue.push(level);                 }                 continue;             }                          final_level.insert(node_front);             node_set.erase(node_front);                          set<int>::iterator iter = edge_map[node_front].begin();             for(; iter != edge_map[node_front].end();iter++){                 if (*iter == pre[node_front])                     continue;                 if (node_set.find(*iter) != node_set.end()) {                     if (pre[*iter] != 0) {                         is_tree = false;                         continue;                     }                     pre[*iter] = node_front;                     node_queue.push(*iter);                     } else                      is_tree = false;                      }             node_queue.pop();         }     }          if (!is_tree){         cout<<"Error: "<<count<<" components";      } else {         int level2 = -1;         set<int> final2;         node_front = *final_level.begin();                  node_queue.push(node_front);          node_queue.push(level2);                           while(!node_queue.empty()) {             node_front = node_queue.front();                                          if (node_front < 0) {                 level2 --;                 node_queue.pop();                 if (!node_queue.empty()){                     final2.clear();                     node_queue.push(level2);                 }                 continue;             }                          final2.insert(node_front);                          set<int>::iterator iter = edge_map[node_front].begin();             for(; iter != edge_map[node_front].end();iter++){                 if (*iter == pre2[node_front])                     continue;                 pre2[*iter] = node_front;                 node_queue.push(*iter);                 }             node_queue.pop();         }         for (set<int>::iterator iiit = final2.begin(); iiit != final2.end(); iiit++)             if (final_level.find(*iiit) == final_level.end())                 final_level.insert(*iiit);                  for (set<int>::iterator it = final_level.begin(); it != final_level.end(); ){             cout<<*it;             if (++it != final_level.end())                 cout<<endl;         }                           cout<<endl;      }                    return 0;
} 

发表于 2019-02-27 22:46:30 回复(0)
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;

//1021 Deepest Root
//寻找使高度最大的根结点
//如果这样的结点不唯一,按增序输出
//如果给的图不是树,输出"Error: K components"
//结点下标1~N

/**************************
*这是在大神的代码基础上改的
*我调整了bug之后能过PAT和牛客。
*而且速度奇快!!!
*并查集nb!!!
***************************/

const int maxn = 10005;
vector<int> map[maxn]; //邻接表

//并查集计算连通图个数
int father[maxn];

//初始化并查集
void init(int n) {
    for (int i = 0; i <= n; ++i) {//此处一定要有等号
        father[i] = i;
    }
}

//查找根节点
int getfather(int x) {
    if (x != father[x]) {
        father[x] = getfather(father[x]);
    }
    return father[x];
}

//合并两个元素所在的集合,返回是否有环
void Union(int x, int y) {
    x = getfather(x);
    y = getfather(y);
    if (x != y) {
        father[x] = y;
    }
}
//并查集结束

//DFS
vector<int> visited;
int deepest;
set<int> res;

void DFS(int i, int distance) {
    if (distance > deepest) {
        res.clear();
        res.insert(i);
        deepest = distance;
    }
    else if (distance == deepest) {
        res.insert(i);
    }

    visited[i] = 1;
    for (unsigned int j = 0; j < map[i].size(); ++j) {
        if (!visited[map[i][j]]) {
            //visited[map[i][j]] = 1;
            DFS(map[i][j], distance + 1);
            //visited[map[i][j]] = 0;
        }
    }
    visited[i] = 0;
}


int main() {

    int n, from, to;
    cin >> n;
    init(n);    //初始化并查集

    //n-1条边
    for (int i = 1; i < n; ++i) {
        cin >> from >> to;
        Union(from, to);
        map[from].push_back(to);
        map[to].push_back(from);
    }

    int cnt = 0;   //连通分量的个数
    for (int i = 1; i <= n; ++i) {
        if (father[i] == i) {
            cnt++;
        }
    }

    visited.resize(n + 1, 0);

    if (cnt>1) {
        cout << "Error: " << cnt<< " components" << endl;
        return 0;
    }

    set<int> trees;

    //随便找个点1开始第一次深度搜索找到最远的点
    DFS(1, 1);

    //第一次找到的点一定是最后需要的那个根节点之一
    for (auto it = res.begin(); it != res.end(); ++it) {
        trees.insert(*it);
    }

    //从最远的点开始第二次搜索
    int point = (*res.begin());
    DFS(point, 1);
    for (auto it = res.begin(); it != res.end(); ++it) {
        trees.insert(*it);
    }

    //set内部升序
    for (auto it = trees.begin(); it != trees.end(); ++it) {
        cout << *it << endl;
    }

    return 0;
}

发表于 2019-01-24 16:10:51 回复(0)
思路: 参考大佬
对于并查集推荐 https://blog.csdn.net/u013546077/article/details/64509038
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
#include <vector>
#include <fstream>
using namespace std;

const int size = 10000;

#ifndef debug
ifstream ifile("case.txt");
//freopen ("case.txt","r",stdin);
#define cin ifile
#endif

class DisjointSet
{
private:
    int *T, size, sum;
    int FindRoot(int i)
    {
        return T[i] < 0 ? i : (T[i] = FindRoot(T[i]));
    }
public:
    DisjointSet(int _size) :size(_size)
    {
        T = new int[size];
        Init();
    }
    void Init()
    {
        sum = size;
        memset(T, -1, sizeof(int)*size);
    }
    bool Unioned(int i, int j)
    {
        return FindRoot(i) == FindRoot(j);
    }
    void Union(int i, int j)//合并领导层
    {
        if ((i = FindRoot(i)) != (j = FindRoot(j)))// 不是连通的把一个领导层换掉
        {
            T[i] = T[i] + T[j];
            T[j] = i;
            sum--;
        }//如果是连通的就不用做任何事情
    }
    int FindSum(int i)// 返回所有的节点的深度
    {
        return -T[FindRoot(i)];
    }
    int SumOfUnits()// 返回没有来连通的个数。
    {
        return sum;
    }
    ~DisjointSet()
    {
        delete[] T;
    }
};

vector<int> v[10000];// 这种存储方式是存储的孩子节点
int vis[10000];
void dfs(int i, int dist, int & Max)
{
    vis[i] = dist;
    Max = max(Max, vis[i]);
    for (int k = 0; k < v[i].size(); k++)
    {
        if (vis[v[i][k]] == -1)
        {
            dfs(v[i][k], dist + 1, Max);
        }
    }
}

int main()
{
    int i, j, temp;
    int n;
    cin >> n;
    DisjointSet ds(n);
    for (i = 0; i < n - 1; i++)
    {
        int a, b;
        cin >> a >> b;
        a--, b--;
        v[a].push_back(b);
        v[b].push_back(a);
        ds.Union(a, b);// 合并领导层这么说他们是连通的
    }
    if (ds.SumOfUnits() == 1)// 全部是在一个连通图里面
    {
        int start, Max;
        set<int> s;
        for (Max = start = i = 0; i < 2; i++)// 遍历两边就可以得到全部的最长的节点
        {
            memset(vis, -1, sizeof(vis));// 因为要遍历两次所以清空一下。
            dfs(start, 0, Max);
            for (j = 0; j < n; j++)
            {
                if (vis[j] == Max)// 记录层数量,如果是叶子层且节点最深那么就把她们记录下来
                {
                    s.insert(j);
                }
            }
            start = *s.begin();// 这个点可以任意取一个值
        }
        for (set<int>::iterator it = s.begin(); it != s.end(); it++)
        {
            printf("%d\n", (*it) + 1);
        }
    }
    else// 如果不是一棵连通图那么就输出总共连通的单位
    {
        printf("Error: %d components\n", ds.SumOfUnits());
    }
    system("pause");
    return 0;
    
}

--------------------------------------
直接使用两个DFS即可
一个计算树高一个计算真正的最高的root。  计算最高的root 参考  别人的博客。
#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
#include <set>
using namespace std;

const int maxn = 10010;
vector<int> v[maxn];
bool visit[maxn];
int maxH = 0;
vector<int> temp;
vector<int> ans;
set<int> s;
void DFS(int x){
    if(visit[x] == true){
        return;
    }
    visit[x] = true;
    for(int i=0; i<v[x].size(); i++){
        DFS(v[x][i]);
    }
}


void DFS1(int x,int height){
    if(visit[x] == true){
        return;
    }
    visit[x] = true;
    if(height > maxH){
        temp.clear();
        maxH = height;
        temp.push_back(x);
    }else if(maxH == height){
        temp.push_back(x);
    }
    for(int i=0; i<v[x].size(); i++){
        DFS1(v[x][i], height+1);
    }
}



int main(){
    //freopen("case.txt","r",stdin);
    int N;
    scanf("%d",&N);
    int a,b;
    // 初始化连通集
    //init();
    for(int i=1; i<N; i++){
        scanf("%d%d",&a,&b);
        v[a].push_back(b);
        v[b].push_back(a);
    }
    memset(visit, false, sizeof(visit));
    int count = 0;
    for(int i=1; i<= N; i++){
        if(!visit[i]){
            DFS(i);
            count++;
        }
    }
    if(count > 1){
        printf("Error: %d components\n",count);
        return 0;
    }else{
        memset(visit, false, sizeof(visit));
        DFS1(1,1);
        memset(visit, false, sizeof(visit));
        ans = temp;
        DFS1(ans[0],1);
        for(int i=0; i<temp.size(); i++){
            s.insert(temp[i]);
        }
        for(int i=0; i<ans.size(); i++){
            s.insert(ans[i]);
        }
        for(set<int>::iterator i=s.begin(); i != s.end(); i++){
            /*if(i == s.begin()){
                printf("%d",*i);
            }else{
                printf(" %d",*i);
            }*/
            printf("%d\n",*i);
        }
    } 
}

编辑于 2019-03-19 21:11:56 回复(0)
邻接表存储图,并查集求连通分量个数,层序遍历求深度


#include<stdio.h>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
int parent[10001];
int visited[10001];

int root(int i){
    while(parent[i]>=0)
        i=parent[i];
    return i;
}
void unionNode(int r1,int r2){
    if(parent[r1]>parent[r2]){
        parent[r2]+=parent[r1];parent[r1]=r2;
    }else{
        parent[r1]+=parent[r2];parent[r2]=r1;
    }
}
int main(){
    int n;
    scanf("%d",&n);
    vector<int> e[10001];
    fill(parent,parent+10000,-1);
    int r1,r2;
    int e1,e2;
    for(int i=0;i<n-1;i++){
        scanf("%d %d",&e1,&e2);
        e[e1].push_back(e2);
        e[e2].push_back(e1);
        r1=root(e1);
        r2=root(e2);
        if(r1!=r2)//构建并查集
            unionNode(r1,r2);
    }
    int count=0;
    for(int i=1;i<=n;i++){
        if(parent[i]<0)
            count++;
    }
    if(count!=1){
        printf("Error: %d components",count);
        return 0;
    }
    int deep=0,tag,l;
    vector<int> roots;
    for(int i=1;i<=n;i++){//分别求deep
        if(e[i].size()>1)//必存在度为一的顶点,最深树根必在其中
            continue;

        queue<int> level;
        tag=i;l=0;level.push(i);
        fill(visited,visited+10000,false);
        visited[i]=true;
        while(!level.empty()){
            int t=level.front();
            level.pop();
            for(auto it=e[t].begin();it!=e[t].end();it++){
                if(!visited[*it]){//未访问邻接边入队
                    level.push(*it);
                    visited[*it]=true;
                }
            }
            if(t==tag&&!level.empty()){
                l++;tag=level.back();
            }
        }//while
        if(l>deep){
            deep=l;roots.clear();roots.push_back(i);
        }else if(l==deep){
            roots.push_back(i);
        }
    }

    sort(roots.begin(),roots.end());

    for(int i=0;i<roots.size();i++){
        printf("%d\n",roots[i]);
    }
    getchar();
    getchar();
    return 0;
}

编辑于 2018-08-13 21:09:20 回复(1)
#include<cstring>
#include<cstdio>
#include<vector>
#include<set>
#include<iostream>
using namespace std;
const int maxn=10010;
vector<int> G[maxn];
int  N;
int father[maxn];
bool vis[maxn]={false};
set<int> temp,ans;
void init()
{
    for(int i=1;i<=N;i++)
     {
            father[i]=i;
            vis[i]=false;
     }
}
int findFather(int x)
{
    int a=x;
    while(x!=father[x])
        x=father[x];
    //father[a]=x
    while(a!=father[a])
    {
        int z=a;
        a=father[a];
        father[z]=x;
    }
    return x;
}
void Union(int u,int v)
{
    int fau=findFather(u);
    int fav=findFather(v);
    if(fau!=fav)
        father[fau]=fav;
}
int maxHeight=0;
void DFS(int root,int height)
{
    vis[root]=1;
    if(height>maxHeight)
    {
        temp.clear();
        temp.insert(root);
        maxHeight=height;
    }
    if(height==maxHeight)
    {
        temp.insert(root);
    }
    for(int i=0;i<G[root].size();i++)
        if(vis[G[root][i]]==false)
           DFS(G[root][i],height+1);
}
int main()
{
    cin>>N;
    init();
    for(int i=1;i<=N-1;i++)
    {
        int c1,c2;
        cin>>c1>>c2;
        G[c1].push_back(c2);
        G[c2].push_back(c1);
        Union(c1,c2);
    }
    int block=0;
    for(int i=1;i<=N;i++)
    {
        int fa=findFather(i);
        if(vis[fa]==false)
        {
            block++;
            vis[fa]=true;
        }
    }
    if(block!=1) cout<<"Error: "<<block<<" components"<<endl;
    else
    {
       memset(vis,0,sizeof(vis));
       DFS(1,1);
       ans=temp;
       memset(vis,0,sizeof(vis));
       DFS(*(ans.begin()),1);
       set<int>::iterator it;
       for(it=temp.begin();it!=temp.end();it++)
           ans.insert(*it);
       for(it=ans.begin();it!=ans.end();it++)
            cout<<*it<<endl;
    }
}

编辑于 2018-06-11 23:51:55 回复(0)
这个题需要求解两个问题,第一个是连通图个数的问题,一个是求解最长路径的问题。
对问题一:连通图个数的问题,采用并查集的解法,这种解法一般用来求解集合的个数等问题

对问题二:解题报告提出了一种两次dfs确定最远端点的解法。通过第一次dfs,可以得到对节点最远的一个节点;第二次dfs就可以得到相对端点一最远的节点。此时得到的节点便是问题的解
发表于 2016-05-05 14:37:34 回复(0)
啥头像
证明解答报告里为什么两次深搜能找出所有距离最远的点

因为树中最远的距离必是距离根节点R最远和次远的两个叶节点的连线,其中这里的根节点R可随意设置一个。
只要找出最远的距离的两个节点,这两个节点可相互为deepest root。
最远距离的两个节点可能存在多对。

第一次深搜找出离根节点R最远的叶节点(或者是次远的叶节点)。
    之所以能任意选一个点开始,是因为无论选哪个点a,距离a最远的点必是
    距离根节点R最远的叶节点(或者是次远的叶节点)
第二次深搜找出最远距离线上的另一端点。
可能存在多对
发表于 2016-03-04 16:37:59 回复(0)