ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: lee1892

[讨论] 来个难度高点的:用最快的方法找出一个树内距离最远的两个节点间的距离

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2014-11-21 09:56 | 显示全部楼层
本帖最后由 wcymiss 于 2014-11-21 10:32 编辑
Moneky 发表于 2014-11-21 09:53
4;2,1;3,1;2,4
这是什么意思?
   3    2


你应该这样看:                 或者这样:                                      再或者这样:                                这样也行:

          1                                       2                                                   3                                               4
         /  \                                    /   \                                                /                                                /
       2     3                                4     1                                            1                                               2
      /                                                 \                                          /                                                /
   4                                                    3                                       2                                               1
                                                                                                 /                                               /
                                                                                               4                                              3

点评

不是逗号前面的是逗号后面的爸爸么,也就是 父,子  发表于 2014-11-21 10:14

TA的精华主题

TA的得分主题

发表于 2014-11-21 10:18 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
Moneky 发表于 2014-11-20 16:30
先扔一块砖。
无脑穷举法,基本上3分钟内可以求出(用附件中的代码生成的数据),没有仔细看过数据,但怎么 ...

楼主没说逗号前面是父,后面是子啊。

TA的精华主题

TA的得分主题

发表于 2014-11-21 10:24 | 显示全部楼层
wcymiss 发表于 2014-11-21 10:18
楼主没说逗号前面是父,后面是子啊。

没有说也得统一啊,你前面发的  ××××2$就是那样的

TA的精华主题

TA的得分主题

发表于 2014-11-21 10:31 | 显示全部楼层
Moneky 发表于 2014-11-21 10:24
没有说也得统一啊,你前面发的  ××××2$就是那样的

看9楼我的提问和楼主10楼的回复

TA的精华主题

TA的得分主题

发表于 2014-11-21 10:45 | 显示全部楼层
wcymiss 发表于 2014-11-21 10:31
看9楼我的提问和楼主10楼的回复

我理解错了,其实逗号只表示两个点相连。不看成什么父父子子君君臣臣的。

TA的精华主题

TA的得分主题

发表于 2014-11-21 12:28 | 显示全部楼层
本帖最后由 wcymiss 于 2014-11-24 08:21 编辑

.............................................................

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-11-21 14:22 | 显示全部楼层
本帖最后由 lee1892 于 2014-11-21 15:10 编辑

这个题目,我基本上就是按之前的几个提示来分析的:
1、明确题目中的树是这样的一个图:
    不存在孤立节点,不存在回路 即 任一节点到另一个节点必然存在且仅存在唯一路径(经过的边不重复)
2、基于以上特点,就可以回答前面提示的第三个问题,任一节点都可以视作根节点。
3、对于提示的第二个问题,前面有人给出了实例给予了否定。那么进一步的猜测,就是既然距离最远的两节点不一定都是距离根节点最远的,那么是不是有一个必然是?试证明如下:
    假设根节点为O,相互距离最远的两节点分别为 P1 和 P2,而存在一个距离根节点 O 更远的一个节点,设为 Q,如果我们能够证明 Q 到 P1 或 P2 的距离 必有一个大于 P1 到 P2 的距离,就可以证明前面的猜测是正确的。    记 P1 到 P2 的距离为:|P1 - P2|,类似的 |O - Q|...
    有:|O - Q| > |O - P1|,|O - Q| > |O - P2|
    由上述 1 知,P1 到 P2 的路径必然经过其共有上溯节点,设为 A,则 |P1 - A| <= |P1 - O|,|P2 - A| <= |P2 - O|
    有:|P2 - P1| = |P2 - A| + |A - P1|
    有如下两种情况:
    a、Q 到 O 不经过 A,则 |Q - P1| = |Q - A| + |A - P1|
        如果 Q 到 A 经过 O,则 |Q - A| = |Q - O| + |O - A| > |P2 - O| >= |P2 - A|,所以 |Q - P1| > |P2 - P1|
        如果 Q 到 A 不经过 O,则 Q、A 必然有一个共有上溯节点 B,B 为 A 到 O 间的一个节点,于是 |Q - A| = |Q - B| + |B - A| = |Q - O| - |O - B| + |B - A|
                而 |P2 - A| = |P2 - B| - |B - A| = |P2 - O| - |O - B| - |B - A|,所以 |Q - A| > |P2 - A|,所以 |Q - P1| > |P2 - P1|
    b、Q 到 O 经过 A,则有两种可能:
        Q 在 A 到 P1 或 P2 的某条分支上的分支,设为 P2,设 Q 和 P2 的共有上溯节点为 B,则 |Q - P1| = |Q - B| + |B - A| + |A - P1| = |Q - O| - |O - B| + |B - A| + |A - P1|
                而 |P2 - A| = |P2 - O| - |O - B| + |B - A| ........
        Q 与 P1、P2 的共有上溯节点为 A,则 |Q - P1| = |Q - A| + |A - P1| = |Q - O| - |O - A| + |A - P1| .........
4、既然距离最远的两个节点必有一个距离根节点最远,就可以以任一节点开始,先找到距离其最远的节点,再由此节点始再次找到与其最远的节点,就可以获得距离最远的两个节点的距离了。

最终,问题归结为 如何最快的找到距离根节点最远的节点

注:共有上溯节点指两个节点到根节点的路径中的第一个共有节点。
以上。

点评

不是可以两天内写代码的么。应该在后天开贴啊。  发表于 2014-11-21 22:14

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-11-21 14:58 | 显示全部楼层
本帖最后由 lee1892 于 2014-11-21 15:06 编辑

一个广度优先的遍历查找,利用队列来实现迭代计算:
  1. Public Function LongestPath(ByVal strTree As String) As Long
  2.     Dim nSize&, aData, aTree(), i&, aCnt&(), nA&, nB&, aTemp&()
  3.     aData = Split(strTree, ";")
  4.     nSize = CInt(aData(0)) ' 第一个元素为节点数量
  5.     ReDim aTree(1 To nSize), aCnt(1 To nSize)
  6.     For i = 1 To nSize
  7.         ReDim aTemp(1 To nSize)
  8.         aTree(i) = aTemp ' 建立复合数组
  9.     Next
  10.     For i = 1 To UBound(aData)
  11.         nA = CInt(Split(aData(i), ",")(0)): nB = CInt(Split(aData(i), ",")(1))
  12.         ' 相互连接的两节点的编号
  13.         aCnt(nA) = aCnt(nA) + 1:            aCnt(nB) = aCnt(nB) + 1
  14.         ' 某节点的连接节点数量计数
  15.         aTree(nA)(aCnt(nA)) = nB:           aTree(nB)(aCnt(nB)) = nA
  16.         ' 建立连接
  17.     Next
  18.     ReDim aTemp(1 To nSize) ' 临时数组重置用以记录节点到根节点的距离
  19.     nA = BFS_Iterative(aTree, aCnt, 1, aTemp)  ' 距离根节点 1# 最远的节点编号
  20.     ReDim aTemp(1 To nSize) ' 重置临时数组
  21.     nB = BFS_Iterative(aTree, aCnt, nA, aTemp)  ' 距离根节点 nA 最远的节点编号
  22.     LongestPath = aTemp(nB) ' 返回距离值
  23.     Erase aTree: Erase aTemp: Erase aCnt: Erase aData
  24. End Function

  25. Private Function BFS_Iterative&(ByRef aTree(), ByRef aCnt&(), ByVal nInd&, ByRef aDist&())
  26.     ' aTree:以元素下标为节点编号的数组,其元素为该节点所连接的节点编号的数组
  27.     ' aCnt:以元素下标为节点编号的数组,其元素为该节点所连接的节点的数量
  28.     ' nInd:当前遍历的起始节点编号
  29.     ' aDist:以元素下标为节点编号的数组,其元素为该节点至起始节点的距离值
  30.     ' 返回值:距离起始节点最远的节点编号
  31.     Dim i&, nCurInd&, nMaxDist&, nMInd&
  32.     Dim aPathed() As Boolean
  33.     Dim cQue As New Collection
  34.     ReDim aPathed(1 To UBound(aTree)) ' 记录某节点是否已经查找过
  35.     aPathed(nInd) = True ' 起始节点设置为已查找过
  36.     cQue.Add nInd ' 用 集合 模拟队列,添加起始节点进入队列
  37.     While cQue.Count > 0 ' 当队列不为空时循环
  38.         nCurInd = cQue(1) ' 当前节点为队列中的第一个节点
  39.         cQue.Remove 1 ' 删除队列中的第一个节点
  40.         aPathed(nCurInd) = True ' 设置当前节点为已查找过
  41.         For i = 1 To aCnt(nCurInd) ' 遍历查找当前节点的连接节点
  42.             If Not aPathed(aTree(nCurInd)(i)) Then ' 如果该连接节点未查找过,则
  43.                 cQue.Add aTree(nCurInd)(i) ' 将该连接节点添加到队列中
  44.                 aDist(aTree(nCurInd)(i)) = aDist(nCurInd) + 1 ' 该连接节点距起始节点的距离为当前节点的距离 + 1
  45.             End If
  46.         Next
  47.     Wend
  48.     ' 找到距离起始节点最远的节点编号
  49.     For i = 1 To UBound(aDist)
  50.         If aDist(i) > nMaxDist Then nMaxDist = aDist(i): nMInd = i
  51.     Next
  52.     BFS_Iterative = nMInd
  53.     Set cQue = Nothing
  54. End Function
复制代码

TA的精华主题

TA的得分主题

发表于 2014-11-21 22:08 | 显示全部楼层
lee1892 发表于 2014-11-21 14:22
这个题目,我基本上就是按之前的几个提示来分析的:
1、明确题目中的树是这样的一个图:
    不存在孤立节 ...

看到你这一大段 O 啊 P 啊 Q的我就晕了。

我只记得小时候玩钥匙圈,一大堆钥匙圈串在一起,拎起其中一个,找到垂得最低的那个圈,再拎起这个圈,就能找到最长的链子。原理要我证明的话,可能会非常啰嗦。

我那个是“深度优先递归”么?我不晓得什么是“深度优先”、“广度优先”,只是听说过这个名词。

递归溢出刚测了下,没有分叉的5000个节点溢出,4999个可以运行。

改成非递归的:

  1. Private Sub GetNodeLenght2(NodeIndex As Integer, NodeLength As Integer)
  2.     Dim i As Integer
  3.     Dim j As Integer
  4.     Dim N As Integer
  5.     Dim arr(), intPos As Integer
  6.     ReDim arr(1 To UBound(arrTree))
  7.     intPos = 1
  8.     arr(intPos) = NodeIndex
  9.     arrNodeLength(NodeIndex) = NodeLength
  10.     Do
  11.         i = i + 1
  12.         For j = 1 To arrNodeCount(arr(i))
  13.             N = arrTree(arr(i))(j)
  14.             If arrNodeLength(N) = 0 Then
  15.                 arrNodeLength(N) = arrNodeLength(arr(i)) + 1
  16.                 intPos = intPos + 1
  17.                 arr(intPos) = N
  18.             End If
  19.         Next
  20.     Loop Until i = intPos
  21.     MaxLength = arrNodeLength(arr(i))
  22.     MaxNodeIndex = arr(i)
  23. End Sub
复制代码



点评

哈哈,两次!  发表于 2014-11-22 00:53
哦,貌似有问题呀,最远的不见得是你队列里最后添加的那个哦  发表于 2014-11-22 00:51
这个就是广度优先了,你那个arr就是用来模拟队列的  发表于 2014-11-22 00:39

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-11-22 00:46 | 显示全部楼层
wcymiss 发表于 2014-11-21 22:08
看到你这一大段 O 啊 P 啊 Q的我就晕了。

我只记得小时候玩钥匙圈,一大堆钥匙圈串在一起,拎起其中一 ...

这个题里我最得意的就是题目分析乐,再就是这个证明了,我觉得这是我能做到的最好的数学描述了[得意]

总不能说就是就是嘛~

溢出的问题我没试,但估计10000层递归怎么也干掉了,果然言中,嘿嘿~

点评

看你这么得意,我就耐心点,去看看那一大片的O啊Q啊的  发表于 2014-11-22 21:21
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-19 12:21 , Processed in 0.046625 second(s), 6 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表