题目链接: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*20];
void init(){memset(head,-1,sizeof(head));for(int i=1;i<=n;i++)pre[i]=i;cnt=flag=0;
}
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]=0;q.push(u);while(!q.empty()){u=q.front();q.pop();vis[u]=true;for(int i=head[u];i!=-1;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=1;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=1;else{pre[x]=y;add(u,v,w);add(v,u,w);}}if(flag){printf("YES\n");continue;}memset(vis,0,sizeof(vis));memset(dis,0,sizeof(dis));stack<int>ss;//因为可能给的数据是森林,不一定是只有一棵树,所以我把每颗树里面//离树根最远的点存进栈里面 for(int i=1;i<=n;i++){if(vis[i])continue;max1=0;bfs(i);ss.push(point);}int ans=0;memset(vis,0,sizeof(vis));memset(dis,0,sizeof(vis)); while(!ss.empty()){//再用栈里面的点来进行第二次bfs找到树的直径的另外一个点和树的直径 point=ss.top();ss.pop();max1=0;bfs(point);ans=max(max1,ans);}printf("%d\n",ans);}return 0;
}

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*20];
void init(){memset(head,-1,sizeof(head));for(int i=1;i<=n;i++)pre[i]=i;cnt=flag=0;max1=0;
}
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!=-1;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=1;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=1;else{pre[x]=y;add(u,v,w);add(v,u,w);}}if(flag){printf("YES\n");continue;}int ans=0;memset(vis,0,sizeof(vis));queue<int>q;//用队列来存第一次dfs找出的所有点 for(int i=1;i<=n;i++){if(vis[i])continue;dfs(i);q.push(point);max1=0;}memset(dis,0,sizeof(dis));memset(vis,0,sizeof(vis));while(!q.empty()){point=q.front();q.pop();max1=0;dfs(point);ans=max(ans,max1);}printf("%d\n",ans);}return 0;
}

转载于:https://www.cnblogs.com/6262369sss/p/10016190.html

求树的直径+并查集(bfs,dfs都可以)hdu4514相关推荐

  1. PAT甲级1021 Deepest Root :[C++题解]树的最大深度、并查集、dfs求树的深度

    文章目录 题目分析 题目链接 题目分析 分析: 考察知识点:并查集.dfs.树的深度 给定n个结点,n-1条边,只要能保证只有1个连通分量,就是一棵树.否则的话就不是树,它是不连通的. 用并查集来看是 ...

  2. HDU4612+Tarjan缩点+BFS求树的直径

    tarjan+缩点+树的直径 题意:给出n个点和m条边的图,存在重边,问加一条边以后,剩下的桥的数量最少为多少. 先tarjan缩点,再在这棵树上求直径.加的边即是连接这条直径的两端. 1 /* 2 ...

  3. hdu 4607 Park Visit 求树的直径

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607 Claire and her little friend, ykwd, are travelli ...

  4. 树上子链(树形dp求树的直径)

    树上子链 题意: 给定一棵树 T ,树 T 上每个点都有一个权值. 定义一颗树的子链的大小为:这个子链上所有结点的权值和 . 请在树 T 中找出一条最大的子链并输出. 题解: 求树的直径,题目中存在负 ...

  5. Problem K. Road Network - ACPC2015(求树的直径 dp)

    Problem K. Road Network 题目链接 Arab Collegiate Programming Contest 2015 题意: 树形的公路,如果阻塞道路可以断开两个区域彼此的连接, ...

  6. 求树的直径的两种方法

    树的直径 树型dp求树的直径 优缺点: 优点为可以处理边权为负的情况,但不易得到直径的路径(指树的直径经过什么点). 代码模板: #include<bits/stdc++.h> using ...

  7. 《鲁滨逊漂流记》题解(LCA算法求树的直径)

    Description <鲁滨逊漂流记>只讲到了鲁滨逊在岛上建立起一个自给自足的生态环境.而大家不知道的是,在此之后,鲁滨逊因为太无聊,开始探索周边的岛屿,一共 NNN 天.鲁滨逊第 11 ...

  8. HDU - 6393 Traffic Network in Numazu(线段树+LCA+树链剖分+并查集)

    题目链接:点击查看 题目大意:给出一个由n个点和n条边组成的图,每条边都有权值,题目保证图是连通的,然后给出m个询问,每次询问分为两种形式: 0 x y:将第x条边的权值修改为y 1 x y:查询x- ...

  9. F - Warm up - hdu 4612(缩点+求树的直径)

    题意:有一个无向连通图,现在问添加一条边后最少还有几个桥 分析:先把图缩点,然后重构图为一棵树,求出来树的直径即可,不过注意会有重边,构树的时候注意一下 *********************** ...

最新文章

  1. python中列表和集合_15个例子掌握Python列表,集合和元组
  2. Pri3D:一种利用RGB-D数据固有属性完成3D场景感知的表示学习方法
  3. 编程方法学26:介绍Java标准库
  4. android播放html5视频,仅仅有声音没有图像视频
  5. docker 网络_初探Docker的网络模式
  6. Android BaseAdapter应用基础
  7. 服务器搭建及微信开发
  8. SENT协议(SAE-J2716)
  9. IntelliJ IDEA 2020 如何解决Commit: Local Changes Refresh提交Git代码卡住超级慢(已解决)
  10. 基于STM32的ch438串口扩展芯片使用
  11. 产品运营 第一章(黄有璨)
  12. 纵横三国外挂手记(1) 分析篇
  13. wpf写我的世界启动器教程1
  14. 为何丧尸只会攻击人类,而不“咬”动物?
  15. ml-agents_使用ML-Agents的自玩功能来训练智能对手
  16. 鼠标点击页面出现富强自由等文字JS特效
  17. 深度学习:维度灾难(Curse Of Dimensionality)
  18. 金蝶K3物料后台启用/取消保质期/批次管理
  19. 如何用Github钩子做自动部署
  20. 一种低成本eDP转LVDS接口方案

热门文章

  1. command shortcut paste
  2. 关于Servlet报错:405 HTTP method GET is not supported by this URL问题解决方法
  3. ArcGIS 栅格函数在线调用详解
  4. 600个开源iOS应用库
  5. iOS程序员必须知道的Android要点
  6. StrangeIoC —— Unity MVC 专属框架
  7. FLEX AIR添加系统托盘图标步骤
  8. DXUT框架剖析(2)
  9. 1.Echarts的坑:切换tab时,echart显示默认的100px
  10. python编写数据库连接工具_详解使用Python写一个向数据库填充数据的小工具(推荐)...