树的直径,树的最长路dp思想

dp一直弱死了,树型dp很多基本的题都不会,最近在刷树型dp的题,把关于树的最长路的思想总结一下:

树的直径:树中距离最远的两点间的距离。

下面说几道题:

hdu 2196:对于树上(双向边)的每一个节点求出与其距离最远的点的距离。

这个主要用的思想是两次dfs:一次dfs将无向图转化为有跟树(所以一开是一定要是建双向边,不然很可能wa或者tle,记录过程中可以开数组记入父亲节点,也可以在dfs递推过程中以栈的形式记录)求出每个跟节点到其所有的叶子节点的最远距离f[i]和g[i]。再一次dfs求出能够由父亲节点转化得到的最大距离h[i],求h[i]的过程中就有可能用到f[i]和g[i]了,因为如果i节点在其父亲j节点的最远距离f[j]中,那么f[i]就只能由g[j]或者h[j]得到,不然就由f[j]或者h[j]得到,具体可能说的不是特别清。两个dfs综合起来的复杂度只有O(E)

poj 1985:求树的直径。个人觉得大概有3种方法。

第一种是如上题hdu2196的写法,求出每个点的最远距离最后取最大值,这样不会增加太多的复杂度,因为每次dfs也都知识O(E)的复杂度。

View Code
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<vector>
 7 using namespace std;
 8 const int maxn = 40005;
 9 int f[maxn], g[maxn], h[maxn], longest[maxn];
10 vector<int> son[maxn], w[maxn];
11 
12 int dfs(int root, int pre){
13     int i, j;
14     int est = 0, esti=-1, er=0;
15     if(f[root]!=-1) return f[root];
16     if(son[root].empty()) return f[root] = 0;
17     for(i=0;i<son[root].size();i++){
18         if(pre!=son[root][i]){
19             if(dfs(son[root][i],root)+w[root][i]>est){
20                 est = f[son[root][i]]+w[root][i];
21                 esti = i;
22             }
23         }
24     }
25     longest[root] = esti;
26     for(i=0;i<son[root].size();i++){
27         if(pre!=son[root][i]){
28             if(f[son[root][i]]+w[root][i]>er&&i!=longest[root]){
29                 er = f[son[root][i]]+w[root][i];
30             }
31         }
32     }
33     g[root] = er;
34     return f[root] = est;
35 }
36 
37 void dfs1(int root, int pre){
38     int i, j;
39     for(i=0;i<son[root].size();i++){
40         if(pre!=son[root][i]){
41             if(i!=longest[root]){
42                 h[son[root][i]] = max(h[root],f[root])+w[root][i];
43             }
44             else{
45                 h[son[root][i]] = max(h[root],g[root])+w[root][i];
46             }
47             dfs1(son[root][i],root);
48         }
49     }
50 }
51 
52 void Init(int n){
53     int i;
54     for(i=0;i<=n;i++){
55         f[i] = g[i] = h[i] = longest[i] = -1;
56         son[i].clear();
57         w[i].clear();
58     }
59 }
60 int main(){
61     int i, j, k, n, m, ans;
62     int x1, x2, l;
63     char opt;
64     while(~scanf("%d%d",&n,&m)){
65         Init(n);
66         for(i=0;i<m;i++){
67             scanf("%d%d%d",&x1,&x2,&l);
68             scanf(" %c",&opt);
69             son[x1].push_back(x2);w[x1].push_back(l);
70             son[x2].push_back(x1);w[x2].push_back(l);
71         }
72         for(i=1;i<=n;i++){
73             if(f[i]==-1){
74                 f[i] = dfs(i,-1);
75                 h[i] = 0; dfs1(i,-1);
76             }
77         }
78         ans = 0;
79         for(i=1;i<=n;i++){
80             ans = max(ans,max(f[i],h[i]));
81         }
82         printf("%d\n",ans);
83     }
84     return 0;
85 }

第二种是利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点。这样就可以首先任取一个点,bfs求出离其最远的点,在用同样的方法求出离这个叶子节点最远的点,此时两点间的距离就是树的直径。

View Code
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<vector>
 7 #include<queue>
 8 using namespace std;
 9 const int maxn = 40005;
10 vector<int> son[maxn], w[maxn];
11 bool vis[maxn], viss[maxn];
12 int f[maxn];
13 int bfs(int root){
14     int i, j, k;
15     int ans = root, maxx = 0;
16     queue<int> q;
17     memset(vis,0,sizeof(vis));
18     memset(f,0,sizeof(f));
19     q.push(root);
20     vis[root] = 1;f[root] = 0;viss[root] = 1;
21     while(!q.empty()){
22         root = q.front();
23         q.pop();
24         for(i=0;i<son[root].size();i++){
25             if(vis[son[root][i]]==0){
26                 q.push(son[root][i]);
27                 vis[son[root][i]] = 1;viss[son[root][i]] = 1;
28                 f[son[root][i]] = f[root]+w[root][i];
29                 if(maxx<f[son[root][i]]){
30                     maxx = f[son[root][i]];
31                     ans = son[root][i];
32                 }
33             }
34         }
35     }
36     return ans;
37 }
38 int solve(int root){
39     int  u, v;
40     u = bfs(root);
41     v = bfs(u);
42     return f[v];
43 }
44 int main(){
45     int i, j, k, n, m;
46     int x1, x2, l, u;
47     int res;
48     char opt;
49     while(~scanf("%d%d",&n,&m)){
50         for(i=0;i<=n;i++){
51             son[i].clear();
52             w[i].clear();
53         }
54         for(i=0;i<m;i++){
55             scanf("%d%d%d",&x1,&x2,&l);
56             scanf(" %c",&opt);
57             son[x1].push_back(x2);w[x1].push_back(l);
58             son[x2].push_back(x1);w[x2].push_back(l);
59         }
60         res = 0;
61         memset(viss,0,sizeof(vis));
62         for(i=1;i<=n;i++){
63             if(viss[i]==0){
64                 res = max(res,solve(i));
65             }
66         }
67         printf("%d\n",res);
68     }
69     return 0;
70 }

ps:搜索也可以用dfs的方法搜,不过个人觉得bfs虽然更长,但比较好写,不容易出错。

第三种方法应该也可以算是树的直径的一个性质了吧,树的直径的长度一定会是某个点的最长距离f[i]与次长距离g[i]之和。最后求出max{f[i]+g[i]}就可以了,用到方法1中的第一个dfs就行了

View Code
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<vector>
 7 using namespace std;
 8 const int maxn = 40005;
 9 int f[maxn], g[maxn], longest[maxn];
10 vector<int> son[maxn], w[maxn];
11 int dfs(int root, int pre){
12     int i, j;
13     int est = 0, esti=-1, er=0;
14     if(f[root]!=-1) return f[root];
15     if(son[root].empty()) return f[root] = 0;
16     for(i=0;i<son[root].size();i++){
17         if(pre!=son[root][i]){
18             if(dfs(son[root][i],root)+w[root][i]>est){
19                 est = f[son[root][i]]+w[root][i];
20                 esti = i;
21             }
22         }
23     }
24     longest[root] = esti;
25     for(i=0;i<son[root].size();i++){
26         if(pre!=son[root][i]){
27             if(f[son[root][i]]+w[root][i]>er&&i!=longest[root]){
28                 er = f[son[root][i]]+w[root][i];
29             }
30         }
31     }
32     g[root] = er;
33     return f[root] = est;
34 }
35 
36 void Init(int n){
37     int i;
38     for(i=0;i<=n;i++){
39         f[i] = g[i] = longest[i] = -1;
40         son[i].clear();
41         w[i].clear();
42     }
43 }
44 int main(){
45     int i, j, k, n, m, ans;
46     int x1, x2, l;
47     char opt;
48     while(~scanf("%d%d",&n,&m)){
49         Init(n);
50         for(i=0;i<m;i++){
51             scanf("%d%d%d",&x1,&x2,&l);
52             scanf(" %c",&opt);
53             son[x1].push_back(x2);w[x1].push_back(l);
54             son[x2].push_back(x1);w[x2].push_back(l);
55         }
56         for(i=1;i<=n;i++){
57             if(f[i]==-1){
58                 f[i] = dfs(i,-1);
59             }
60         }
61         ans = 0;
62         for(i=1;i<=n;i++){
63             ans = max(ans,f[i]+g[i]);
64         }
65         printf("%d\n",ans);
66     }
67     return 0;
68 }

树的直径应该就是以上几种方法了吧,不过从poj1985的三种方法可以得出用搜索的方法求某个点的最远的点的距离了,就是先对任意一个点求距离其最远的顶点,最后可以得到一条树的直径的两个端点,以这两个端点开始去遍历整棵树,两个端点到每个点的距离较大值就会是这个点在树上能够走的最远距离。手画了几个sample,觉得如果树有多条直径,这个结论也应该是正确的。

转载于:https://www.cnblogs.com/celia01/archive/2012/07/30/2615842.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434377.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

xLite连接asterisk提示sip408错误

xLite连接asterisk提示sip408错误 1.sip408应答代码全文 408 Request Timeout 在一段时间内&#xff0c;服务器不能产生一个终结应答&#xff0c;例如&#xff0c;如果它无法及时决定用户的位置。客户端可以在稍后不更改请求的内容然后重新尝试请求。 2.原因&#xff1a;造成…

linux sd卡 读写速度测试_铠侠(原东芝存储)SD卡,大容量存储时代,高速读写选择...

作为一个经常出去旅行的旅游博主&#xff0c;在旅行过程中&#xff0c;还是有很多拍摄的需求。无论是存储美图&#xff0c;还是视频&#xff0c;一个大容量、安全可靠的储存卡还是很有必要的。这既可以缓解因为容量不够&#xff0c;频繁导数据的尴尬。又不会因为数据丢失&#…

软件测试需求分析录音,谈一谈软件测试需求分析

在软件测试过程中我们首先要做的就是分析测试需求&#xff0c;一般都是由客户方给出&#xff0c;测试需求应该全部覆盖已定义的业务流程&#xff0c;以及功能和非功能方面的需求。分析软件测试需求是一个不可或缺的步骤&#xff0c;因为它有利于保证测试的质量和进度&#xff0…

hdu 4324 Triangle LOVE

http://acm.hdu.edu.cn/showproblem.php?pid4324 比赛的时候 脑子又短路了 “between A and B, if A don’t love B, then B must love A” 这句话读题的时候倒是看到了 思考方法的时候却忘了 伤不起呀 我们把喜欢自己的人数定为入度的话 假设到了第n1个人 那么前n个人 两两…

potplayer 多个进程_操作系统 | 进程同步与进程互斥

主题 进程同步与进程互斥 01进程同步 问题在多道批处理系统中&#xff0c;多个进程是并发执行的&#xff0c;而并发执行的进程具有异步性&#xff0c;也就是说&#xff0c;各个进程以各自独立的、不可预知的速度向前推进。这样会带来什么问题呢&#xff1f;如果有 AB…

Asterisk拨号方案常用函数说明

Asterisk拨号方案常用函数说明 (1)Answer() 应用于接听正在响铃通道,它不需要任何参数. (2)Playback() 应用在通道上播放事先录制好的语音文件.指定一个文件名(不带扩展名),可以使用绝对路径与相对路径. (3)Hangup() 应用在于挂断一个正在活动的通道. (4)Background() 它…

计算机指令int,汇编入门学习笔记 (十二)—— int指令、端口

疯狂的暑假学习之 汇编入门学习笔记 (十二)—— int指令、端口参考&#xff1a; 《汇编语言》 王爽 第13、14章一、int指令1. int指令引发的中断int n指令&#xff0c;相当于引发一个n号中断。执行过程相当于&#xff1a;(1)取中断类型吗n。(2)标志寄存器入栈&#xff1b;设置…

Java中间件:淘宝网系统高性能利器

【TechTarget中国原创】淘宝网是亚太最大的网络零售商圈&#xff0c;其知名度毋庸置疑&#xff0c;吸引着越来越多的消费者从街头移步这里&#xff0c;成为其忠实粉丝。如此多的用户和交易量&#xff0c;也意味着海量的信息处理&#xff0c;其背后的IT架构的稳定性、可靠性也显…

@autowired注解 抽象类_别再用ifelse了,用注解去代替他吧

来自公众号&#xff1a;咖啡拿铁策略模式经常在网上看到一些名为“别再if-else走天下了”&#xff0c;“教你干掉if-else”等之类的文章&#xff0c;大部分都会讲到用策略模式去代替if-else。策略模式实现的方式也大同小异。主要是定义统一行为(接口或抽象类)&#xff0c;并实现…

卸载mysql8.0卸载程序_程序卸载失败,来使用微软官方的Windows卸载工具试试

在我们实际的Windows操作系统使用中&#xff0c;总会遇到一些程序无法成功卸载的情况。当然&#xff0c;我们可以使用第三方软件来进行尝试卸载。要么&#xff0c;第三方软件会进行收费。要么&#xff0c;免费的会带给你捆绑软件的安装或者烦人的广告。还可能会造成系统文件的误…

Asterisk文件目录

目录 说明 /etc/asterisk Asterisk主目录,包含其它关于Asterisk的配置文件;  *zaptel.conf这个配置文件放在/etc,因为其它软件也可以使用Zaptel这个硬件及其驱动,所以不是放在/etc/asterisk里. /usr/lib/asterisk/modules 这个目录包含所有可以加载Asterisk模块(应用程序…

英特网rst服务器未在运行,技术员示范win7系统提示“英特尔(R)RST服务未在运行”的详细办法...

不知道大家有没有遇到过win7系统提示“英特尔(R)RST服务未在运行”的问题&#xff0c;最近有很多朋友来向我咨询win7系统提示“英特尔(R)RST服务未在运行”的问题如何解决&#xff0c;于是小编就个大家整理的win7系统提示“英特尔(R)RST服务未在运行”的解决步骤&#xff0c;就…

初识临时表

临时表就是那些名称以井号 (#) 开头的表。如果当用户断开连接时没有除去临时表&#xff0c;SQL Server 将自动除去临时表。临时表不存储在当前数据库内&#xff0c;而是存储在系统数据库 tempdb 内。 创建临时表有多种方法。其一&#xff0c;先创建表结构&#xff0c;跟创建普…

小米手机电池恢复代码_解决小米手机屏幕问题的方法

屏幕在我们的小米手机中永远不会失败&#xff0c;因为没有它&#xff0c;我们将无法使用可用的应用程序和功能。为了帮助大家&#xff0c;我们汇总了小米和Redmi手机中最常见的问题&#xff0c;为您提供了针对我们所面临的每种情况的解决方案。MIUI定制层汇集了适用于小米手机的…

Asterisk拨号方案语法基础

Asterisk语法基础 extensions.conf(四部分:context,extension,priorities,application) context:用于对extensions组命名,把拨号方案的不同部分进行分离,免得交织在一起。 表示方法是把名字放在[]的中间,名字只能用a~z,A~Z,0~9,以及连字号和下划线组成(空格不在允许的字符里…

使用promise解决回调地狱_「每日一题」Promise 是什么?

window.Promise 已经是 JS 的一个内置对象了。1. Promise 有规格文档吗&#xff1f;2. 你一般如何使用 Promise。-----------目前的 Promise 都遵循 Promises/A 规范。英文规范&#xff1a;https://promisesaplus.com/中文翻译&#xff1a;图灵社区 : 阅读 : 【翻译】Promises/…

应用css div进行页面布局设计,利用CSS与DIV进行页面布局.ppt

《利用CSS与DIV进行页面布局.ppt》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《利用CSS与DIV进行页面布局.ppt(6页珍藏版)》请在人人文库网上搜索。1、利用CSS与DIV进行页面布局,学习目标&#xff1a;,理解CSSDIV网页布局的含义掌握网页结构的规划掌握CSS样式的创建…

【原】winform高效导出Excel带格式设置

参考网上的方法修改&#xff0c;1000条记录导出只要3S&#xff08;1GRDM,C2.8CPU&#xff09;.1.项目添加excel对象类库的引用&#xff0c;Microsoft Excel 11.0 object library&#xff08;不同版本的Excel&#xff0c;类库不同&#xff0c;这是2003的&#xff09; 2.代码1//-…

vscode 逗号不换行_来自一个插件的疯狂夸赞,VS Code「彩虹屁」插件问世,网友:我想要郭德纲版...

听说有人开发了「虚拟程序员鼓励师」&#xff0c;安装使用后的我疯狂捶墙&#xff0c;导致我家变成了单间。机器之心报道&#xff0c;机器之心编辑部。你可能从未想过&#xff0c;会有这么一个人&#xff1a;对你写的每一行代码都不吝夸赞&#xff0c;知道你什么时候想骂人&…

Asterisk拨号方案中变量的应用

在拨号方案中使用变量可以减少打字、增加清晰度,也有助于在拨号方案中加入逻辑. 这里的变量有全局变量,通道变量和环境变量。 1.全局变量 全局变量应该在extensions.conf文件的开始利用[globals]这个context定义或利用 SetGlobalVar()应用.如: [globals] 80000Zap/1或 [inter…