题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5374

思路:题目的意思是求树上的两点,使得树上其余的点到其中一个点的最长距离最小。可以想到这题与树直径有关,我们可以这样做,首先求出树的直径,然后取出树的中点以及与该中点相邻,并且是直径上的一个点,这样就把这棵树划分为两颗子树,然后分别求出这两棵树的直径,最后要选择的两个点分别就是这两棵树的直径上的中点。

一开始是用dfs写的,结果爆栈了,改成bfs就过了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; const int MAX_N = (200000 + 20000);
struct Edge {
int v, w, next;
} edge[MAX_N << 1]; int N, NE, head[MAX_N];
void Init()
{
NE = 0;
memset(head, -1, sizeof(head));
} void Insert(int u, int v, int w)
{
edge[NE].v = v;
edge[NE].w = w;
edge[NE].next = head[u];
head[u] = NE++;
} int dep[MAX_N], path[MAX_N], st, ed, s_mid, e_mid;
int ans_minDist, ans_point1, ans_point2;
bool vis[MAX_N]; bool check(int u, int v)
{
if (u == s_mid && v == e_mid) return true;
if (u == e_mid && v == s_mid) return true;
return false;
} void bfs(int u, int fa, int deep)
{
dep[u] = deep;
path[u] = fa;
vis[u] = true;
queue<int > que;
que.push(u); while (!que.empty()) {
int u = que.front();
que.pop(); for (int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].v, w = edge[i].w;
if (v == fa || check(u, v) || vis[v]) continue;
dep[v] = dep[u] + w;
path[v] = u;
vis[v] = true;
que.push(v);
}
}
} void gao()
{
s_mid = e_mid = -1;
memset(vis, false, sizeof(vis));
bfs(1, -1, 0); int max_deep = -1;
for (int i = 1; i <= N; ++i) {
if (dep[i] > max_deep) max_deep = dep[i], st = i;
} memset(vis, false, sizeof(vis));
bfs(st, -1, 0); max_deep = -1;
for (int i = 1; i <= N; ++i) {
if (dep[i] > max_deep) max_deep = dep[i], ed = i;
} int tmp = ed, cnt = 0;
while (tmp != -1) {
tmp = path[tmp];
++cnt;
if (cnt == max_deep / 2) s_mid = tmp;
else if (cnt == max_deep / 2 + 1) e_mid = tmp;
}
} void solve()
{
//get point1
memset(vis, false, sizeof(vis));
bfs(s_mid, e_mid, 0); int max_deep = -1;
for (int i = 1; i <= N; ++i) {
if (vis[i] && dep[i] > max_deep) max_deep = dep[i], st = i;
} memset(vis, false, sizeof(vis));
bfs(st, -1, 0); max_deep = -1;
for (int i = 1; i <= N; ++i) {
if (vis[i] && dep[i] > max_deep) max_deep = dep[i], ed = i;
} int tmp = ed, cnt = 0;
ans_point1 = ed;
while (tmp != -1) {
tmp = path[tmp];
++cnt;
if (cnt == max_deep / 2) ans_point1 = tmp;
} memset(vis, false, sizeof(vis));
bfs(ans_point1, -1, 0); max_deep = -1;
for (int i = 1; i <= N; ++i) {
if (vis[i] && dep[i] > max_deep) max_deep = dep[i];
} ans_minDist = max_deep; //get point2
memset(vis, false, sizeof(vis));
bfs(e_mid, s_mid, 0); max_deep = -1;
for (int i = 1; i <= N; ++i) {
if (vis[i] && dep[i] > max_deep) max_deep = dep[i], st = i;
} memset(vis, false, sizeof(vis));
bfs(st, -1, 0); max_deep = -1;
for (int i = 1; i <= N; ++i) {
if (vis[i] && dep[i] > max_deep) max_deep = dep[i], ed = i;
} tmp = ed, ans_point2 = ed, cnt = 0;
while (tmp != -1) {
tmp = path[tmp];
++cnt;
if (cnt == max_deep / 2) ans_point2 = tmp;
} memset(vis, false, sizeof(vis));
bfs(ans_point2, -1, 0); max_deep = -1;
for (int i = 1; i <= N; ++i) {
if (vis[i] && dep[i] > max_deep) max_deep = dep[i];
} ans_minDist = max(ans_minDist, max_deep); } int main()
{
int Cas;
scanf("%d", &Cas);
while (Cas--) {
scanf("%d", &N); Init();
for (int i = 1; i < N; ++i) {
int u, v;
scanf("%d %d", &u, &v);
Insert(u, v, 1);
Insert(v, u, 1);
} if (N == 2) {
puts("0 1 2");
continue;
} gao();
solve(); printf("%d %d %d\n", ans_minDist, ans_point1, ans_point2);
}
}


zoj 3820(2014牡丹江现场赛B题)的更多相关文章

  1. zoj 3827(2014牡丹江现场赛 I题 )

    套公式 Sample Input 33 bit25 25 50 //百分数7 nat1 2 4 8 16 32 3710 dit10 10 10 10 10 10 10 10 10 10Sample ...

  2. zoj 3819(2014牡丹江现场赛 A题 )

    题意:给出A班和B班的学生成绩,如果bob(A班的)在B班的话,两个班级的平均分都会涨.求bob成绩可能的最大,最小值. A班成绩平均值(不含BOB)>A班成绩平均值(含BOB) &&a ...

  3. 2014 牡丹江现场赛 i题 (zoj 3827 Information Entropy)

    I - Information Entropy Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %l ...

  4. ZOJ 3822 ( 2014牡丹江区域赛D题) (概率dp)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5376 题意:每天往n*m的棋盘上放一颗棋子,求多少天能将棋盘的每行每列都至少有 ...

  5. 2014 牡丹江现场赛 A.Average Score(zoj 3819) 解题报告

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5373 题目意思: 有两个class:A 和 B,Bob 在 Clas ...

  6. ZOJ 2819 Average Score 牡丹江现场赛A题 水题/签到题

    ZOJ 2819 Average Score Time Limit: 2 Sec  Memory Limit: 60 MB 题目连接 http://acm.zju.edu.cn/onlinejudge ...

  7. 2014牡丹江 现场赛 F zoj 3824 Fiber-optic Network

    首先赞一下题目, 好题 题意: Marjar University has decided to upgrade the infrastructure of school intranet by us ...

  8. zoj 3809 枚举水题 (2014牡丹江网赛 A题)

    题目大意:给出一列取样的几个山的高度点,求山峰有几个? Sample Input 291 3 2 4 6 3 2 3 151 2 3 4 5Sample Output 30 # include < ...

  9. ACM学习历程——ZOJ 3822 Domination (2014牡丹江区域赛 D题)(概率,数学递推)

    Description Edward is the headmaster of Marjar University. He is enthusiastic about chess and often ...

随机推荐

  1. php cli配置文件问题

    引言 今天在教别人使用protobuf的时候,无意中发现了一个php cli模式下的诡异问题,费了老半天的找到解决方法了,这里拿出来分享下. 问题描述 我们这边最先引入了protobuf协议,使用的是 ...

  2. elk系列5之syslog的模块使用

    preface rsyslog是CentOs系统自带的的一个日志工具,那么我们就配置logstash来接受rsyslog的日志. logstash的syslog模块 linux-node2上操作 lo ...

  3. python中文分词:结巴分词

    中文分词是中文文本处理的一个基础性工作,结巴分词利用进行中文分词.其基本实现原理有三点: 基于Trie树结构实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图(DAG) 采用了动态规 ...

  4. 各种HTTP状态的含义

    在网站建设的实际应用中,容易出现很多小小的失误,就像MySQL当初优化不到位,影响整体网站的浏览效果一样,其实,网站的常规http状态码的表现也是一样,Google无法验证网站几种解决办法,提及到由于 ...

  5. 第二轮冲刺-Runner站立会议09

    今天:将日历界面和主程序结合起来 明天:查看整个项目,调试是否有问题

  6. thinkphp分页二,分装到funciton.php

    function.php代码 <?php /* 全局分页 * $table 数据表名 * $order 排序 * $pagesize 每页显示N个 * $where 查询条件 * $rollPp ...

  7. [Unity] Shader - CG语言 和 HLSL语言

    CG 跟 HLSL几乎是一摸一样的. (HLSL官方参考,包含语法格式,函数库,关键字,在这个地方: http://msdn.microsoft.com/en-us/library/bb509638( ...

  8. [NHibernate]事务

    目录 写在前面 文档与系列文章 事务 增删改查 总结 写在前面 上篇文章介绍了nhibernate的增删改查方法及增加修改操作,这篇文章将介绍nhibernate的事务操作. SQL Server中的 ...

  9. Pandas-多表操作

    Pandas包对多个数据表(DataFrame)的常用整合功能. 目录 merge join concat append combin_first merge 合并 pandas.merge可根据一个 ...

  10. 【JWT】JWT+HA256加密 Token验证

    目录 Token验证 传统的Token验证 JWT+HA256验证 回到顶部 Token验证 最近了解下基于 Token 的身份验证,跟大伙分享下.很多大型网站也都在用,比如 Facebook,Twi ...