ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

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

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2014-11-20 11:03 | 显示全部楼层
本帖最后由 yiyiyicz 于 2014-11-20 11:07 编辑
kangatang 发表于 2014-11-20 09:11
支持你,只因为你讲的有道理。看问题有深度,可以让思路更加开阔


其实我也是在开一个排产的帖子时,遇到了一个就是图论范畴的算法。推敲教科书给的方法,发现在特例的情况下不行,后在EH中也查到了这个算法(教科书没有代码),依然是特例不行。而这种特例在数学中算作特例,可是在实际中却是时常会出现。于是发现,EH中有些算法经不起推敲
当然,那个帖子就先放在了那里。解决同样的问题,还有其他的算法。只是需要时间把原理写成VB/VBA的代码
这些,对于非软件、数学专业,而且是在业余琢磨的我们来说,只能等有时间再折腾它了。
我只是提醒各位,在EH中看到的代码、算法,作为参考没有问题,但要派用场解决问题时,务必小心。我们要的是解决实际问题,华而不实会招来麻烦的
从EH的VBA版块看,有几人的写代码还是挺棒的,没有发现有严重漏洞。关键是发帖的介绍要到位,自己心里一定要清清楚楚

点评

哦,没时间写代码呀。木有问题呀,您写个伪代码,描述清楚算法就行哦~~就1楼这个简单的卑微的无聊的小问题,您就别掖着了  发表于 2014-11-20 11:52

TA的精华主题

TA的得分主题

发表于 2014-11-20 12:56 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 kangatang 于 2014-11-20 13:13 编辑

玩游戏学到的技能都用上了

都闲得蛋疼。不再理会,下午还有一车砖去搬一下。

点评

真棒!  发表于 2014-11-20 13:24

TA的精华主题

TA的得分主题

发表于 2014-11-20 14:17 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
太丧心病狂了。大冷天的的,怎么还有火苗了,有火带给大家温暖烤烤就行,可千万不要把人点燃了。 预留个位置关注一下。

TA的精华主题

TA的得分主题

发表于 2014-11-20 14:26 | 显示全部楼层
lee1892 发表于 2014-11-14 14:37
下述代码可以按题目格式生成一个随机树的字符串

这样好像更随机些:(随机选择父节点)

  1. Function RandomTree2$()
  2.     Dim nCnt%, i%, nInd%, nLast%, nChildNumMax%
  3.     Randomize
  4.     nCnt = Int(Rnd * 100) + 1 '总节点个数
  5.     nChildNumMax = 10 '每个节点最多拥有子节点个数
  6.     RandomTree2 = CStr(nCnt)
  7.     For i = 2 To nCnt
  8.         nInd = Int(Rnd * (i - 1)) + 1 '从比自己小的节点中选择一个作为父节点
  9.         nLast = i
  10.         RandomTree2 = RandomTree2 & ";" & CStr(nInd) & "," & CStr(nLast)
  11.     Next
  12. End Function
复制代码

点评

这逆向思维![再强一个]  发表于 2014-11-20 15:26
这个真乱,子节点数量控制不需要了[强]  发表于 2014-11-20 15:19

TA的精华主题

TA的得分主题

发表于 2014-11-20 14:27 | 显示全部楼层
本帖最后由 wcymiss 于 2014-11-21 09:34 编辑

再上个更随机的:
  1. Function RandomTree3$() '随机根节点,随机顺序,随机父子关系
  2.     Dim nCnt%, i%, nInd%, nLast%
  3.     Dim arr%(), r%, j%
  4.     Randomize
  5.     nCnt = Int(Rnd * 10) + 1 '总节点个数
  6.     RandomTree3 = CStr(nCnt)
  7.    
  8.     ReDim arr(1 To nCnt) '洗牌
  9.     For i = 1 To nCnt
  10.         arr(i) = i
  11.     Next
  12.     For i = nCnt To 1 Step -1
  13.         r = Int(Rnd * i) + 1
  14.         j = arr(r)
  15.         arr(r) = arr(i)
  16.         arr(i) = j
  17.     Next
  18.    
  19.     For i = 2 To nCnt '随机选择“父”节点
  20.         nInd = arr(Int(Rnd * (i - 1)) + 1)
  21.         nLast = arr(i)
  22.         If Rnd < 0.5 Then
  23.             RandomTree3 = RandomTree3 & ";" & CStr(nInd) & "," & CStr(nLast)
  24.         Else
  25.             RandomTree3 = RandomTree3 & ";" & CStr(nLast) & "," & CStr(nInd)
  26.         End If
  27.     Next
  28. End Function
复制代码
除了断号,其他的应该都有了。断号也不难,只是后续处理多了些代码。

点评

这个简单,在前面那个基础上用一个乱序数组取序数就是了  发表于 2014-11-21 15:13

TA的精华主题

TA的得分主题

发表于 2014-11-20 16:30 | 显示全部楼层
本帖最后由 Moneky 于 2014-11-20 23:39 编辑

先扔一块砖。
无脑穷举法,基本上3分钟内可以求出(用附件中的代码生成的数据),没有仔细看过数据,但怎么最长的才几十这个数量级,难道一个节点有N多个儿子?
  1. Public Function LongestPath(ByVal strTree As String) As Long
  2. '    Dim s As String
  3.     Dim arr, brr
  4.     Dim i As Long, j As Long, t As Long, lCount As Long, N() As Long
  5.     Dim maxI As Long, maxJ As Long, maxC As Long
  6.     Dim d As New Dictionary
  7.     LongestPath = 1
  8. '    s = "8;1,2;1,3;2,4;2,6;3,5;5,7;5,8"
  9. '    arr = Split(s, ";")
  10. arr = Split(strTree, ";")
  11.     lCount = CLng(arr(0))
  12.     ReDim N(1 To lCount)
  13.     For i = 1 To UBound(arr)
  14.         brr = Split(arr(i), ",")
  15.         N(CLng(brr(1))) = CLng(brr(0))
  16.     Next
  17.     For i = 2 To lCount - 1
  18.         For j = i + 1 To lCount
  19.             t = N(j): c = 0
  20.             If t = i Then c = 1: GoTo V_END
  21.             Do
  22.                 c = c + 1
  23.                 d(t) = c
  24.                 t = N(t)
  25.                 If t = i Then c = c + 1: GoTo V_END1
  26.             Loop Until t = 0
  27.             t = N(i): c = 1
  28.             If t = j Then c = 1: GoTo V_END1
  29.             Do
  30.                 If d(t) > 0 Then
  31.                     c = c + d(t)
  32.                     GoTo V_END1
  33.                 Else
  34.                     c = c + 1
  35.                     d(t) = c
  36.                     t = N(t)
  37.                     If t = j Then c = c + 1: GoTo V_END1
  38.                 End If
  39.             Loop Until t = 0
  40. V_END1:
  41.             d.RemoveAll
  42.             
  43. V_END:
  44.             Debug.Print i, j, c
  45.             If c > LongestPath Then LongestPath = c ': maxI = i: maxJ = j
  46.         Next
  47.     Next
  48. End Function
复制代码

晕,原来没有考虑到下面点评中的情况,直接剔除了1号节点了。当然代码改改还是比较容易的,只需改成:
  1. Public Function LongestPath(ByVal strTree As String) As Long
  2.     '    Dim s As String
  3.     Dim arr, brr
  4.     Dim i As Long, j As Long, t As Long, lCount As Long, n() As Long
  5.     '    Dim maxI As Long, maxJ As Long, maxC As Long
  6.     Dim d As New Dictionary
  7.     LongestPath = 1
  8.     '    s = "8;1,2;1,3;2,4;2,6;3,5;5,7;5,8"
  9.     '    arr = Split(s, ";")
  10.     arr = Split(strTree, ";")
  11.     lCount = CLng(arr(0))
  12.     ReDim n(1 To lCount)
  13.     For i = 1 To UBound(arr)
  14.         brr = Split(arr(i), ",")
  15.         n(CLng(brr(1))) = CLng(brr(0))
  16.     Next
  17.     For i = 1 To lCount - 1   '其实就只是把这一句的2改成了1
  18.         For j = i + 1 To lCount
  19.             t = n(j): c = 0
  20.             If t = i Then c = 1: GoTo V_END
  21.             Do
  22.                 c = c + 1
  23.                 d(t) = c
  24.                 t = n(t)
  25.                 If t = i Then c = c + 1: GoTo V_END1
  26.             Loop Until t = 0
  27.             t = n(i): c = 1
  28.             If t = j Then c = 1: GoTo V_END1
  29.             Do
  30.                 If d(t) > 0 Then
  31.                     c = c + d(t)
  32.                     GoTo V_END1
  33.                 Else
  34.                     c = c + 1
  35.                     d(t) = c
  36.                     t = n(t)
  37.                     If t = j Then c = c + 1: GoTo V_END1
  38.                 End If
  39.             Loop Until t = 0
  40. V_END1:
  41.             d.RemoveAll
  42.             
  43. V_END:
  44.             '            Debug.Print i, j, c
  45.             If c > LongestPath Then LongestPath = c ': maxI = i: maxJ = j
  46.         Next
  47.     Next
  48. End Function
复制代码




无脑穷举.zip

15.04 KB, 下载次数: 29

点评

4;1,2;2,3;3,4  发表于 2014-11-20 21:52

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2014-11-20 16:42 | 显示全部楼层
lee1892 发表于 2014-11-19 23:24
您这一大堆话,我除了看出来是在搅合以外,愣没看明白在说啥。
要不这样,您要觉得这题easy,您把代码发 ...

这位大神牛的很,您别和人家较劲。
用VBA 实现面向对象,和实践应用23种设计模式的大神,思路和您一样嘛?
还是赶紧上答案吧,俺不会做,等着看呢。

TA的精华主题

TA的得分主题

发表于 2014-11-20 18:03 | 显示全部楼层
看来是曲高和寡,我是来打酱油的
向老师学习!我终于自己搞定正交表了。

TA的精华主题

TA的得分主题

发表于 2014-11-21 09:14 | 显示全部楼层
21号了,发代码了:
  1. Private arrTree()
  2. Private arrNodeLength() As Integer
  3. Private arrNodeCount() As Integer
  4. Private MaxLength As Integer
  5. Private MaxNodeIndex As Integer

  6. Private Sub GetNodeLenght(NodeIndex As Integer, NodeLength As Integer)
  7.     Dim i As Integer
  8.     Dim N As Integer
  9.     arrNodeLength(NodeIndex) = NodeLength
  10.     If MaxLength < NodeLength Then MaxLength = NodeLength: MaxNodeIndex = NodeIndex
  11.     For i = 1 To arrNodeCount(NodeIndex)
  12.         N = arrTree(NodeIndex)(i)
  13.         If arrNodeLength(N) = 0 Then Call GetNodeLenght(N, NodeLength + 1)
  14.     Next
  15. End Sub

  16. Public Function LongestPath(ByVal strTree As String) As Long
  17.     Dim i As Integer
  18.     Dim arr, Temp
  19.     Dim arrNode() As Integer
  20.     Dim Node1 As Integer
  21.     Dim Node2 As Integer
  22.     Dim NodeCount As Integer
  23.     Dim MaxL As Integer
  24.    
  25.     arr = Split(strTree, ";")
  26.     ReDim arrTree(1 To arr(0))
  27.     ReDim arrNode(1 To arr(0))
  28.     ReDim arrNodeCount(1 To arr(0))
  29.     ReDim arrNodeLength(1 To arr(0))
  30.    
  31.     For i = 1 To arr(0)
  32.         arrTree(i) = arrNode
  33.     Next
  34.    
  35.     For i = 1 To UBound(arr)
  36.         Temp = Split(arr(i), ",")
  37.         Node1 = Temp(0)
  38.         Node2 = Temp(1)

  39.         NodeCount = arrNodeCount(Node1) + 1
  40.         arrTree(Node1)(NodeCount) = Node2
  41.         arrNodeCount(Node1) = NodeCount

  42.         NodeCount = arrNodeCount(Node2) + 1
  43.         arrTree(Node2)(NodeCount) = Node1
  44.         arrNodeCount(Node2) = NodeCount
  45.     Next
  46.    
  47.     MaxLength = 0
  48.     Call GetNodeLenght(1, 1)
  49.     ReDim arrNodeLength(1 To arr(0))
  50.     Call GetNodeLenght(MaxNodeIndex, 1)
  51.    
  52.     LongestPath = MaxLength - 1
  53. End Function
复制代码

点评

另外,深度优先的递归可以一次性获得最长距离的,方法比较绕  发表于 2014-11-21 15:15
深度优先递归对于有没有溢出的危险?试了没?  发表于 2014-11-21 15:02
厉害,学习。看不懂,注释下啊  发表于 2014-11-21 11:27

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2014-11-21 09:53 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
wcymiss 发表于 2014-11-20 14:27
再上个更随机的:除了断号,其他的应该都有了。断号也不难,只是后续处理多了些代码。

4;2,1;3,1;2,4
这是什么意思?
   3    2
    \   / \
      1    4
1有两个爸爸
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-19 12:39 , Processed in 0.041395 second(s), 7 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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