PAT-A 1021. Deepest Root(搜索)

题目链接:https://www.patest.cn/contests/pat-a-practise/1021

题意:无环连通图也可以视为一棵树,选定图中任意一点作为根,如果这时候整个树的深度最大,该点称为 deepest root。 给定一个图,按升序输出所有 deepest root。如果给定的图有多个连通分量,则输出连通分量的数量。


要想树的深度最大,那么树跟一定是一个度为1的点,所以我们只需要找到这些点,然后每个点搜一遍得到最大高度,然后按条件输出即可。当然开始得先判联通,我是用深搜判的。

看网上其他人的做法,很多是先随便选一个点搜一遍,找出距离最大的点,以这个点再搜一遍,最后得到的距离最大的点加上这个点即是答案。这样做看似有道理,而且能过,但是有的情况是判断不了的,比如下面这组数据:

in:

5
1 2
1 3
2 4
2 5

out:
3
4
5

因此这种算法虽然效率高但还需要改进。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
vector<int> m[10010];  //邻接表存图 
int vis[10010];
int deg[10010]; //记录度数 
int ans[10010];
int n;
void dfs(int x) {  //判联通 
  vis[x] = 1;
  for (int i = 0; i < m[x].size(); i++) {
    if (!vis[m[x][i]]) dfs(m[x][i]);
  }
}
struct node {
	int id, step;
};
int bfs(int x) {  //找最远距离 
  memset(vis, 0, sizeof(vis));
  queue<node> q;
  node now, next;
  now.id = x, now.step = 0;
  q.push(now);
  vis[x] = 1;
  int maxl = 0;
  while(!q.empty()) {
  	now = q.front();
  	if(now.step > maxl) maxl = now.step;
  	q.pop();
  	for(int i = 0; i < m[now.id].size(); i++) {
  	  if(!vis[m[now.id][i]]) {
  	  	vis[m[now.id][i]] = 1;
  	  	next.id = m[now.id][i], next.step = now.step+1;
  	  	q.push(next);
	  }
	}
  }
  return maxl;
}
int main() {
  cin >> n;
  int x, y;
  for(int i = 0; i < n - 1; i++) {
    cin >> x >> y;
    deg[x]++;
    deg[y]++;
    m[x].push_back(y);
    m[y].push_back(x);
  }
  int cnt = 0;
  for (int i = 1; i <= n; i++) {
    if (!vis[i]) {
      cnt++;
      dfs(i);
    }
  }
  if(cnt == 1) {  //联通分量个数为1 
  	int maxn = 0;
  	for(int i = 1; i <= n; i++) {
  		if(deg[i] == 1) {
  			ans[i] = bfs(i);
  			if(ans[i] > maxn) maxn = ans[i];
		}
	}
	for(int i = 1; i <= n; i++) {
		if(ans[i] == maxn) cout << i << endl;
	}
  }
  else cout << "Error: " << cnt << " components" << endl;
  return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值