【问题标题】:Finding minimum by passing a variable to recursive function with yield通过将变量传递给具有 yield 的递归函数来找到最小值
【发布时间】:2025-12-03 20:25:02
【问题描述】:

让我们说space = [0, 100]

我得到了空间的碎片,并且可能重叠。

例如,

[0, 30], [0, 20], [10, 40], [30, 50], [50, 90], [70, 100]

是一组片段。

从上述集合中选择的跨越整个空间的一组片段的示例是:

[0, 30], [10, 40], [30, 50], [50, 90], [70, 100]

这组片段跨越了整个空间,因为它的所有元素都在 [0, 100] 中

另一个例子是

[0, 30], [30, 50], [50, 90], [70, 100]

这是前面例子中没有[10, 40]的集合。

对于每组片段,可以计算成本。

集合的成本是添加片段的边际成本之和。

将片段添加到集合的边际成本函数由下式给出:

def get_marginal_cost(fragment):
    return RTT + (fragment[1] - fragment[0])/bandwidth

其中RTTbandwidth 是常量。

我正在尝试从一组片段中找到成本最低的子集。

由于这不能用贪心算法解决,我想考虑所有可能的片段集。

我使用Depth First Search 算法来考虑所有可能的情况,将每个片段视为node,并定义片段uv 之间存在edge 如果u[0] < v[0] <= u[1] <= v[1]

叶子节点是以 100 结尾的片段。

通过下面的函数,我能够获得表示(可能)构成整个space 的片段集的所有可能情况的生成器对象。

def dfs(a, start, path=None):
    if path is None:
        path = [start, ]
    if start[1] == space:
        yield path
    for frgmt in a - set(path):
        l = frgmt[0]
        r = frgmt[1]
        if start[0] < l <= start[1] <= r:
            yield dfs(a, frgmt, path + [frgmt, ])

但是,我不确定如何在dfs 函数中使用上面提到的get_marginal_cost 函数,以及如何将minimum 变量传递和更新为dfs 函数,以便找到终止程序的最低成本。

它应该不断地在最小值上加上边际成本,并且只在if start[1] == space:(空格为100)中检查和更新最小值。

一个测试用例,代码在http://ideone.com/oN4jWa

【问题讨论】:

  • 在我看来,您不仅需要传入和传出 dfs,还需要传入和传出到目前为止的成本。
  • 什么是“所有可能的片段集”?那应该是给定的,而不仅仅是空间 [0, 100] 内的所有数字对,对吗?否则我会想象涉及的碎片越少,成本就越低。
  • 因为你的成本函数只涉及边际成本加上一个片段。我想每个新的附加片段都会增加成本:previous score + get_marginal_cost(fragmt)。看来,它涉及的碎片越少,成本就越低。
  • 不一定。边际成本涉及两个因素,分片数量和分片长度。
  • 你能告诉我片段长度的定义是什么吗?

标签: python python-2.7 yield


【解决方案1】:

恐怕我对您现有的代码了解得不够透彻,无法准确看出您哪里出错了(例如,不清楚astartdfs 中是什么)。但是,我想我掌握了您要解决的问题。以下是我自己解决的方法,使用您描述的基本算法:

from operator import itemgetter

def dfs(space, fragments, path=None, cost=0):
    if path == None:
        path = []
        path_end = space[0]
    else:
        path_end = path[-1][1]

    for i, fragment in enumerate(fragments):
        if fragment[0] > path_end: # this fragment would leave a gap (as
            break                  # will all the rest) so we can stop
        elif path_end < fragment[1]: # useless fragments are skipped
            new_path = path + [fragment]
            new_cost = cost + get_marginal_cost(fragment)
            if fragment[1] == space[1]:  # this fragment reaches the end,
                yield new_path, new_cost # so this is a base case
            else:     # recursive case
                for result in dfs(space, fragments[i+1:], # slice frag list
                                  new_path, new_cost):
                    yield result # in Python 3.3 and later, you can skip the
                                 # loop and just use "yield from dfs(...)"

def find_minimum_cost_path(space, fragments):
    fragments.sort(key=itemgetter(0)) # sort by start of the fragments
    path, cost = min(dfs(space, fragments), key=itemgetter(1))
    return path

我通过在查找所有有效路径(使用递归深度优先遍历)和选择最小成本路径(调用min)之间拆分工作,解决了寻找最小成本路径的问题。您可能可以更改dfs 以仅返回它找到的路径的最低成本,但这会有点复杂。为简单起见,我将各个部分分开。

我的dfs 函数的关键在于它仅适用于已排序的片段序列。目前尚不清楚您使用的是哪种数据结构,所以我在find_minimum_cost_path 函数中调用了sorted。如果您的片段已经排序(通过它们的起始元素)并且它们的数据结构可以被切片,那么您可以摆脱这一步。

【讨论】: