2586. How far away ?(HDU)

16 篇文章 0 订阅

题意理解

一个村庄有很多户人家,任意两户人家最多有一条路相连。已知每条路相连的两户人家的编号和长度,求从A户人家到B户人家有多远?

问题分析

LCA+RMQ数据结构,最近公共祖先+区间最小值

转1:首先用图表示村庄的连接情况。使用邻接表存储,使用heads数组存节点信息,使用edges数组存边信息,edges数组的每个元素存边的长度和邻接边的指针(这里用数组表示链表,所以指针其实是边的下标)。

转2:求A户人家到B户人家的最近距离,转化为求A户和B户人家都相连的最近的那个节点C,再基于这个节点C,计算从根到A的距离disA,从根到B的距离disB,从根到C的距离disC,所求距离即为disA+disB-disC*2;

转3:求A户和B户都相连的最近的节点,即是求最近公共祖先的问题,求最近公共祖先的问题转化为求区间最小值问题。

转4:深度优先遍历图,记录下每个节点第一次出现的次序pos,记录下每个节点的欧拉巡游的次序t(即遍历的全路径,节点重复出现),记录下每个节点相对根节点的深度dep。

转4a:对于图上任意两个节点A,B,通过pos数组找到他们出现在欧拉巡游次序t上的位置,这是一个区间(t[A],t[B]),在将这个区间映射到深度dep对应的区间(dep[t[A]], dep[t[B]), 求深度dep这个区间的最小值,即最小深度值,这个深度值对应的位置就是最小公共祖先的编号。

转4b:求深度dep次序中区间的最小值,使用区间最小值算法,此算法的要点是变换区间输入的两个端点位置为一个端点+区间长度。区间长度用2的幂表示。变换的过程是先计算区间长度,然后计算左端点+比区间长度小的最近的2的幂的最小值left、右端点-区间长度小的最近的2的幂对应的新的左端点+比区间长度小的最近的2的幂的最小值right,求left和right的最小值即为左右端点间的最小值。

转4c:求左端点+用2的幂表示的区间长度范围的最小值。需要计算整个dep序列全部可能的情况。容易想到的思路是左端点依次遍历序列,长度计算整个序列的最近的2的幂的值,从0开始遍历。这里可以用动规来处理,思路是,先计算长度为1的值,再计算长度为2的值,再计算长度为2^2的值,...依次类推,长度为2的值可以转化为2个长度为1的值之间的较小值。这样形成一个数组dp。详细推导参见参考2

其他

图的遍历算法是基础的基础,它的一个作用是把图中的信息带出来。学会在递归算法中插入信息以便带出所要的信息。

此题没有做出来,内部信息量着实太大了,消化消化。

dfs的巨大作用认识不到,整个题目做起来步履维艰,这个坑踩得好!

代码链接

https://github.com/xierensong/learngit/blob/master/hdu/2586/h2586.cpp

参考

https://blog.csdn.net/nameofcsdn/article/details/52230548

https://www.topcoder.com/community/data-science/data-science-tutorials/range-minimum-query-and-lowest-common-ancestor/

range-minimum-query-and-lowest-common-ancestor

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值