题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514

这题主要是叫我们求出树的直径,在求树的直径之前要先判断一下有没有环

树的直径指的就是一棵树上面距离最远的两点的距离,有时也可以指最远的两点之间的路径。

至于树的直径怎么求,我们首先要知道一个结论,树上面随便取一点,离这一点最远的那个点一定是树的直径上面的两点中的一点

证明的博客:https://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html

知道了这个结论,我们就可以用两次dfs或者两次bfs来求出树的直径,第一次bfs我们随便拿树上的一个点进行bfs,去找到离他最远的一点,这样我们就找到了树的直径两端上面的一点,然后第二次bfs就以这一点为开始去找到离这一点距离最大的点,得到的这这个点就树的直径两端的另外一个点,这两点之间的距离就是树的直径。

思路:首先我们要判断是否有环,这里用的是并查集,一旦给出的树边上的两点已经在一个集合里面了,说明之前这两点之间就有一条互通的路径,所以加上增加的这条树边就构成了一个环。然后注意这题给出的数据不一定只是一颗树,可能是森林,所以可能有多个树的直径,我们取最大值。

我的代码写的不是很好,绝对不是最优的,仅供参考。

bfs写的代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 1000005
int head[maxn],pre[maxn],dis[maxn],vis[maxn];
int n,m,k,t,cnt,flag,max1,point;
//max1记录每次bfs的最大距离,point记录离树根最远的点
struct node{
int v,w,next;
}edge[maxn*];
void init(){
memset(head,-,sizeof(head));
for(int i=;i<=n;i++)
pre[i]=i;
cnt=flag=;
}
int find(int a){
if(pre[a]==a)
return a;
return pre[a]=find(pre[a]);
}
void add(int u,int v,int w){
edge[++cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
void bfs(int u){//bfs找以点u为子树的所有点里面离点u最远的点和这个最远的距离
queue<int>q;
dis[u]=;
q.push(u);
while(!q.empty()){
u=q.front();
q.pop();
vis[u]=true;
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v;
int w=edge[i].w;
if(!vis[v]){
dis[v]=dis[u]+w;
q.push(v);
if(max1<dis[v]){//更新最远的点和最大距离
max1=dis[v];
point=v;
}
}
}
} }
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
init();
int u,v,w;
for(int i=;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
if(flag)
continue;
int x=find(u);
int y=find(v);
if(x==y)//并查集判断是否有环
flag=;
else{
pre[x]=y;
add(u,v,w);
add(v,u,w);
}
}
if(flag){
printf("YES\n");
continue;
}
memset(vis,,sizeof(vis));
memset(dis,,sizeof(dis));
stack<int>ss;//因为可能给的数据是森林,不一定是只有一棵树,所以我把每颗树里面
//离树根最远的点存进栈里面
for(int i=;i<=n;i++){
if(vis[i])
continue;
max1=;
bfs(i);
ss.push(point);
}
int ans=;
memset(vis,,sizeof(vis));
memset(dis,,sizeof(vis));
while(!ss.empty()){//再用栈里面的点来进行第二次bfs找到树的直径的另外一个点和树的直径
point=ss.top();
ss.pop();
max1=;
bfs(point);
ans=max(max1,ans);
}
printf("%d\n",ans);
}
return ;
}

dfs写的代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 100005
int n,m,k,t,ans,flag,max1,cnt,point;
int dis[maxn],vis[maxn],head[maxn],pre[maxn];
struct node{
int v,next,w;
}edge[maxn*];
void init(){
memset(head,-,sizeof(head));
for(int i=;i<=n;i++)
pre[i]=i;
cnt=flag=;
max1=;
}
int find(int a){
if(pre[a]==a)
return a;
return pre[a]=find(pre[a]);
}
void add(int u,int v,int w){
edge[++cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
void dfs(int u){//求以u为根节点的子树中离点u最远的点已经最大距离
vis[u]=true;
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v;
int w=edge[i].w;
if(!vis[v]){
dis[v]=max(dis[v],dis[u]+w);
if(dis[v]>max1){
point=v;
max1=dis[v];
}
dfs(v);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
init();
int u,v,w;
for(int i=;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
if(flag)
continue;
int x=find(u);
int y=find(v);
if(x==y)
flag=;
else
{
pre[x]=y;
add(u,v,w);
add(v,u,w);
} }
if(flag){
printf("YES\n");
continue;
}
int ans=;
memset(vis,,sizeof(vis));
queue<int>q;//用队列来存第一次dfs找出的所有点
for(int i=;i<=n;i++){
if(vis[i])
continue;
dfs(i);
q.push(point);
max1=;
}
memset(dis,,sizeof(dis));
memset(vis,,sizeof(vis));
while(!q.empty()){
point=q.front();
q.pop();
max1=;
dfs(point);
ans=max(ans,max1);
}
printf("%d\n",ans);
}
return ;
}

求树的直径+并查集(bfs,dfs都可以)hdu4514的更多相关文章

  1. 【bzoj2870】最长道路tree 树的直径+并查集

    题目描述 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 输入 第一行N 第二行N个数分别表示1~N的点权v[i] 接下来N-1行每 ...

  2. 【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT

    题目描述 给你 $n$ 个点,支持 $m$ 次操作,每次为以下两种:连一条边,保证连完后是一棵树/森林:询问一个点能到达的最远的点与该点的距离.强制在线. $n\le 3\times 10^5$ ,$ ...

  3. hdu 4514(树的直径+并查集)

    湫湫系列故事——设计风景线 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  4. loj6038「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT

    题目传送门 https://loj.ac/problem/6038 题解 根据树的直径的两个性质: 距离树上一个点最远的点一定是任意一条直径的一个端点. 两个联通块的并的直径是各自的联通块的两条直径的 ...

  5. Codeforces 516D - Drazil and Morning Exercise(树的直径+并查集)

    Codeforces 题目传送门 & 洛谷题目传送门 这是一道 jxd 的作业题,感觉难度不是特别大(虽然我并没有自己独立 AC,不过也可能是省选结束了我的脑子也没了罢(((,就随便写写罢 u ...

  6. Codeforces 455C Civilization:树的直径 + 并查集【合并树后直径最小】

    题目链接:http://codeforces.com/problemset/problem/455/C 题意: 给你一个森林,n个点,m条边. 然后有t个操作.共有两种操作: (1)1 x: 输出节点 ...

  7. 求树的直径【两遍BFS】

    两遍BFS.从任意一个点出发,第一遍可以找到直径的一端,从这端出发即可找到另外一端. 证明:从U点出发,到达V[画个图便清晰了] 1.如果U在直径上,则V一定是直径的一个端点. 2.如果U不在直径上. ...

  8. BZOJ 2870: 最长道路tree 树的直径+并查集

    挺好的一道题. 把所有点都离线下来,一个个往里加入就行了. #include <cstdio> #include <algorithm> #define N 100003 #d ...

  9. hdu 4514 湫湫系列故事――设计风景线(求树的直径)

    随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,那就建的越长越好.  现在已经勘探确定了n个位置 ...

随机推荐

  1. angular6新建项目

    mkdir  angular6project cd angular6project ng new demo      新建一个普通项目 ng new demo --routing  新建一个带路由的项 ...

  2. spring-boot入门总结

    1.org.springframework.web.bind.annotation不存在 错误的pom.xml <dependency> <groupId>org.spring ...

  3. Java高级特性 第5节 序列化和、反射机制

    一.序列化 1.序列化概述 在实际开发中,经常需要将对象的信息保存到磁盘中便于检索,但通过前面输入输出流的方法逐一对对象的属性信息进行操作,很繁琐并容易出错,而序列化提供了轻松解决这个问题的快捷方法. ...

  4. OLAP + MDX

    基本概念 维度(Dimension):表示数据的属性,一个维度一般会有一个维表(也可能多个),事实表会有一个字段关联维表. 退化维度:有的维度可以没有维度表,因为这种维度比较简单,没有更多属性,没有必 ...

  5. Delphi XE5 Android 调用手机震动

    uses Androidapi.JNI.Os, Androidapi.JNIBridge; function GetVibratorArray(const AIntArr: array of Int6 ...

  6. Lattice并购案&我国FPGA发展路径

    FPGA作为通信.航天.军工等领域的关键核心器件,是保障国家战略安全的重要支撑基础.近年来,随着数字化.网络化和智能化的发展,FPGA的应用领域得到快速扩张.美国在FPGA领域拥有绝对的垄断优势,已成 ...

  7. 微信小程序如何设置服务器配置

    最近微信小程序在it界火了起来,公司也要求我们开始接触微信小程序,废话不多说直接从配置微信小程序开始 1,首先,登录 https://mp.weixin.qq.com,(这里默认你已经获取到微信小程序 ...

  8. win10环境下Android studio安装教程----亲测可用

    这段时间学习了一下Android的基本开发,发现Google已经停止了对eclipse的支持,并开发了自己的Android开发工具--Android Studio,于是想安装一下Android Stu ...

  9. mysql相关碎碎念

    取得当天: SELECT curdate(); mysql> SELECT curdate();+------------+| curdate()  |+------------+| 2013- ...

  10. BZOJ 4872 luogu P3750 [六省联考2017]分手是祝愿

    4872: [Shoi2017]分手是祝愿 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description ...