博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树的直径,树的最长路dp思想
阅读量:5127 次
发布时间:2019-06-13

本文共 3332 字,大约阅读时间需要 11 分钟。

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
2 #include
3 #include
4 #include
5 #include
6 #include
7 using namespace std; 8 const int maxn = 40005; 9 int f[maxn], g[maxn], h[maxn], longest[maxn];10 vector
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
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
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

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

View Code
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 using namespace std; 9 const int maxn = 40005;10 vector
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
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

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

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

View Code
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 using namespace std; 8 const int maxn = 40005; 9 int f[maxn], g[maxn], longest[maxn];10 vector
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
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
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

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

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

你可能感兴趣的文章
java使用格式String型转成Date型
查看>>
从无到有-在create-react-app基础上接入react-router、redux-saga
查看>>
XML
查看>>
2012年6月编程语言排行榜Top 50:C第1,Java紧随其后
查看>>
解决Shockwave flash在chrome该浏览器崩溃
查看>>
实现一个简单的Unity3D三皮卡——3D Picking (1)
查看>>
JSONObject与JSONArray的使用
查看>>
SQL语句的MINUS,INTERSECT和UNION ALL
查看>>
关于ie兼容css3圆角与阴影与渐变的渲染
查看>>
《java入门第一季》之tcp协议下的编程实现键盘录入数据不断地往服务器端发送数据案例...
查看>>
图片的动画样式
查看>>
JZOJ 1284. 病毒
查看>>
从内存中加载DLL DELPHI版
查看>>
log4j输出多个自定义日志文件(转)
查看>>
APM概述
查看>>
[转]Linux下 tar.xz格式文件的解压方法
查看>>
Java读取其他jar包里的配置文件
查看>>
Python调用selenium
查看>>
mysql日志设置优化
查看>>
Java网络编程
查看>>