簡體   English   中英

Python:找到最長的路徑

[英]Python: Finding the longest path

我有一個簡單的圖形,如下所示

class Job():
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight
        self.depends = []

    def add_dependent(self, dependent):
        self.depends.append(dependent)


jobA = Job('A', 0)
jobB = Job('B', 4)
jobC = Job('C', 2)
jobD = Job('D', 10)
jobE = Job('E', 3)
jobF = Job('F', 11)

jobA.add_dependent(jobB)
jobA.add_dependent(jobC)
jobB.add_dependent(jobD)
jobC.add_dependent(jobE)
jobD.add_dependent(jobF)
jobE.add_dependent(jobF)

所以我們有兩條可能的路徑

A->B->D->F  0+4+10+11 = 25
A->C->E->F  0+2+3+11 = 16

所以最長的路徑是前者

是否有一種簡單的方法來收集最長的路徑, A->B->D->F

def longest_path(root):
    paths = []
    # some logic here
    return paths

print longest_path(jobA) # should print A->B->D->F

不是最有效的解決方案,但這里應該有效:

import operator

def longest_path(root):
    def _find_longest(job):
        costs = [_find_longest(depend) for depend in job.depends]
        if costs:
            # Find most expensive:
            path, cost = max(costs, key=operator.itemgetter(1))
            return ([job.name] + path, job.weight + cost)
        else:
            return ([job.name], job.weight)
    return "->".join(_find_longest(root)[0])

如果您使用OO解決方案,則很容易提供僅存儲最重路徑的方法。 這是我提出的解決方案 - 使用可調用類

In [111]: class Heaviest(object):
     ...:     def __init__(self, job):
     ...:         self.path = ''
     ...:         self.weight = 0
     ...:         self.job = job
     ...:     def _find_heaviest(self, job, path='', weight=0):
     ...:         path += job.name
     ...:         weight += job.weight
     ...:         if not job.depends:
     ...:             if weight > self.weight:
     ...:                 self.weight = weight
     ...:                 self.path = path
     ...:         else:
     ...:             for job in job.depends:
     ...:                 self._find_heaviest(job, path, weight)
     ...:     def __call__(self):
     ...:         self._find_heaviest(self.job)
     ...:         return '->'.join(list(self.path)), self.weight
     ...:                 

In [112]: Heaviest(jobA)()
Out[112]: ('A->B->D->F', 25)

事后的想法:

昨晚我發現,如果出現循環依賴(請參閱我的評論),上面的解決方案將不會產生答案,在達到最大遞歸深度時停止異常。 只需添加下面的行就可以吹掉任何樹遍歷算法 - 而不僅僅是這個算法。

In [226]: jobF.add_dependent(jobA)

In [227]: Heaviest(jobA)()
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-227-94e994624b4e> in <module>()
----> 1 Heaviest(jobA)()

<ipython-input-111-1ff9f69480a9> in __call__(self)
     15                 self._find_heaviest(job, path, weight)
     16     def __call__(self):
---> 17         self._find_heaviest(self.job)
     18         return '->'.join(list(self.path)), self.weight
     19 

<ipython-input-111-1ff9f69480a9> in _find_heaviest(self, job, path, weight)
     13         else:
     14             for job in job.depends:
---> 15                 self._find_heaviest(job, path, weight)
     16     def __call__(self):
     17         self._find_heaviest(self.job)

... last 1 frames repeated, from the frame below ...

<ipython-input-111-1ff9f69480a9> in _find_heaviest(self, job, path, weight)
     13         else:
     14             for job in job.depends:
---> 15                 self._find_heaviest(job, path, weight)
     16     def __call__(self):
     17         self._find_heaviest(self.job)

RuntimeError: maximum recursion depth exceeded

當我試圖修改實施時 - 如果你願意 - 簡單的安全措施可以解決這個問題

def _find_heaviest(self, job, path='', weight=0):
    if not job.name in path:
        path += job.name
        weight += job.weight
        stop_search = not job.depends
    else:
        stop_search = True
    if stop_search:
        if weight > self.weight:

.....

問題解決了

In [230]: Heaviest(jobA)()
Out[230]: ('A->B->D->F', 25)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM