NOIP2017-清北学堂国庆模拟1-Tyvj4865 天天和树

原题
树的直径。严谨的证明还没搞懂。
或许三次BFS可以写个templete缩短代码?

#include <cstdio>
#include <cstring>
using namespace std;
const int MaxN = 1e5;

struct node {
  int vID;
  node *nx;
  node(): 
    vID(-1), nx(NULL) {}
  node(int init_vID, node* init_nx): 
    vID(init_vID), nx(init_nx) {}
};
node *arc[MaxN];

node *newedge; 
void add_edge(int x, int y) {
  newedge = new node(y, arc[x]);
  arc[x] = newedge;
  newedge = new node(x, arc[y]);
  arc[y] = newedge;
}

bool mark[MaxN];
int q1[MaxN], from[MaxN]; 
struct q2_ele {
  int vID, dist;
}q2[MaxN];

int main() {
  freopen("tree.in", "r", stdin);
  freopen("tree.out", "w", stdout);
  int n, i, x, y;
  scanf("%d", &n);
  for (i = 1; i < n; i++) {
    scanf("%d%d", &x, &y);
    x--; y--;
    add_edge(x, y);
  }
  
  //第一遍:找直径的一个端点
  int head, tail, u, s, curr;
  q1[0] = 0;
  mark[0] = true;
  for (head = 0, tail = 1; head != tail; head++) {
    curr = q1[head];
    for (node *adj = arc[curr]; adj != NULL; adj = adj->nx)
      if (!mark[adj->vID]) {
        mark[adj->vID] = true;
        q1[tail] = adj->vID;
        tail++;
      }
    if (head + 1 == tail)
      s = curr;
  }
  
  //第二遍:找出直径上的所有点
  int t, max_dist, curr_vID, curr_dist;
  memset(mark, false, sizeof(mark));
  q2[0] = (q2_ele) {s, 0};
  t = s; max_dist = 0;
  mark[s] = true;
  for (head = 0, tail = 1; head != tail; head++) {
    curr_vID = q2[head].vID; curr_dist = q2[head].dist;
    for (node *adj = arc[curr_vID]; adj != NULL; adj = adj->nx)
      if (!mark[adj->vID]) {
        mark[adj->vID] = true;
        q2[tail] = (q2_ele) {adj->vID, curr_dist + 1};
        from[adj->vID] = curr_vID;
        tail++;
      }
    if (curr_dist > max_dist) {
      t = curr_vID;
      max_dist = curr_dist;
    }
  }
  
  //第三遍:找到距离路径最远的结点
  int ans;
  memset(mark, false, sizeof(mark));
  for (i = t, tail = 0; i != s; i = from[i], tail++) {
    q2[tail] = (q2_ele) {i, 0};
    mark[i] = true;
  }
  mark[s] = true;
  for (head = 0; head != tail; head++) {
    curr_vID = q2[head].vID; curr_dist = q2[head].dist;
    for (node *adj = arc[curr_vID]; adj != NULL; adj = adj->nx)
      if (!mark[adj->vID]) {
        mark[adj->vID] = true;
        q2[tail] = (q2_ele) {adj->vID, curr_dist + 1};
        tail++;
      }
    if (head + 1 == tail)
      ans = curr_dist;
  }
  
  printf("%d\n", ans);
  return 0;
}

转载于:https://www.cnblogs.com/P6174/p/7545634.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值