PAT-A 1021 Deepest Root (25)

  1. Deepest Root (25)

时间限制
1500 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue
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.

Input Specification:

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.

Output Specification:

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.

Sample Input 1:
5
1 2
1 3
1 4
2 5
Sample Output 1:
3
4
5
Sample Input 2:
5
1 3
1 4
2 5
3 4
Sample Output 2:
Error: 2 components

题目大意:给你一个图,有n个节点,n-1条边。求出以其中某一点为根时,构造的树有最大的深度。如果有多个点构造的树的深度都是最大的,那么依次输出;如果该图不是连通图,则输出连通域的个数

分析:跟深度有关,可以选择用bfs。dfs也可以,每次返回访问的点的深度即可,代码量比bfs小。每个点当一次根,每次计算深度时都要访问n个节点,那么时间复杂度为O(N^2)。题目限时1.5s,所以当极限情况下很可能超时,必须要剪枝。

注意到,如果第一次遍历图之后,发现这个图不是连通图,即图中还有未访问过的节点,那么接下来就没必要再把其他点作为根计算深度了。此时由于图中剩余的点都还没访问,所以接下来应当对这些点bfs,把它所在的连通域都访问一遍,再判断是否还有未访问的点,如此往复到所有点都访问完。 每个点都仅被访问一次,那么O(N)。

一开始我的做法是遍历时用并查集统计连通域个数。这样的话,不管该图是否是连通图,依旧会计算所有点作为根的深度,大大浪费时间,导致我有一个case超时了。然后看了别人的题解,才明白

对于题目的限时,假设是1s,我们的时间复杂度不能超过千万级别,如果是o(n^2),则n不能超过3000。 本题是1.5s的限时,但是n是绝对不能超过10000的,所以必须要剪枝。当然,如果真的有n=10000,且是连通图的case,那单纯对所有点用图的遍历就没法做了。

源码如下:

#include<stdio.h>
#include<vector>
#include<queue>

using namespace std;

struct Edge{
  int next;
};

int layer[10001];    //存储以某个节点的深度
bool mark[10001];    //标记访问过
vector<Edge> edge[10001];  
queue<int> Q;
int result[10001];    //存储以某个节点为根的树的深度

int maxLayer = 0;    //最大的深度

int componentCount = 1;    //连通域的个数,至少有一个

int n;




void init(){
  for(int i=1; i<=n; i++){
    layer[i] = 1;
    mark[i] = false;
  }
}


void bfs(int node){

  mark[node] = true;

  Q.push(node);
  int currentPoint;
  int tmpMaxLayer = 0;    //临时存放该树的深度

  while(!Q.empty()){
    currentPoint = Q.front();
    Q.pop();

    for(int i=0; i<edge[currentPoint].size();i++){
      if(!mark[edge[currentPoint][i].next]){    //没访问过 

        mark[edge[currentPoint][i].next] = true;
        layer[edge[currentPoint][i].next] = layer[currentPoint] + 1;
        Q.push(edge[currentPoint][i].next);

        if (tmpMaxLayer < layer[edge[currentPoint][i].next])
          tmpMaxLayer = layer[edge[currentPoint][i].next];


      }
    }
  }

  result[node] = tmpMaxLayer;
  if(tmpMaxLayer > maxLayer)
    maxLayer = tmpMaxLayer;
}

int main(){

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

  for(int i=0; i<n-1; i++){
    scanf("%d%d",&a,&b);
    Edge tmp;
    tmp.next = a;
    edge[b].push_back(tmp);
    tmp.next = b;
    edge[a].push_back(tmp);
  }


  for(int i=1; i<=n; i++){
    if(componentCount == 1)          //如果经过第一次检查发现是连通图,那么初始化后,计算以下一个点位根的树的深度
      init();
    bfs(i);

    for(int j =1; j<=n; j++){        //检查是否是连通图,如果不是连通图则dfs(j),此时就不是遍历所有点计算深度了,而是转而为接下来统计连通域的个数做准备
      if(!mark[j]){
        componentCount ++;
        i = j-1;
        break;
      }
    }
  }


  if(componentCount != 1)
    printf("Error: %d components\n", componentCount);
  else {
    for(int i= 1; i<=n; i++)
      if(result[i] == maxLayer)
        printf("%d\n", i);
  }

  return 0;
}

总结:
1.要提高代码的效率,避免无谓的无用功
2.注意限时
3.不要老用bfs了,下次遇到和深度有关的试试dfs
4.我觉得一开始用并查集太蠢了。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值