【问题标题】:topology sorting拓扑排序
【发布时间】:2016-05-23 14:57:24
【问题描述】:

给定一个有 N 个节点的 DAG,每个节点都有一个值(例如,0.2、0.5、1.3、0.1...)。我想将顶点排序成一个链。难点在于对​​节点进行排序时有一个目标函数。

例如,链是x---> y --->z ---> w。每个链接都有一个权重,对于(x,y)权重= x,链接(y,z)权重= xy,链接(z,w)权重= xyz等等。

目标函数是最小化所有链接权重的总和(此处为链:x+xy+xyz)。

我一直在考虑。但我现在不知道。有没有人可以就算法设计或问题的复杂性证明提供一些想法?谢谢。

【问题讨论】:

  • 贪心对这个有用吗?由于是拓扑排序,每个子问题都独立于父问题。
  • 没有。我不这么认为。这是一个反例:DAG 由两条独立的链组成:1.2---> 0.5 和 1.1--->1.001。优化后的排序链应该是 1.2----> 0.5---->1.1---->1.001。也许对于一种贪婪算法,链应该是:1.1----> 1.001---->1.2 ---> 0.5(最小顶点优先)。你能提供更多关于贪心算法的想法吗?
  • 节点值到底重要还是链接权重重要?
  • @user2585677 你贪婪地选择下一个状态,而不是下一个节点。实际上,它只是状态空间上的 Dijkstra,其中距离是下一个节点的边际成本。这应该在 O(n log n) 中运行,其中 n 是状态数,所以 O(v*2^v),这对于几十个节点来说很好,但不适用于一般的 n。
  • 另外,您的反例与您的问题陈述相矛盾,因为您将链接 (z,w) 的权重定义为 xyz,因此输出只是总和,但我看到您的意思可能是权重是 z,选择该链接的成本是先前权重的乘积。

标签: algorithm sorting graph-algorithm


【解决方案1】:

这是 kevmo314 提到的算法,用 Python 实现。可能它应该在 C 中重新实现,用按位操作代替集合操作。

我们可以重写目标

x + x*y + x*y*z = x*(1 + y*(1 + z)),

所以假设所有的权重都是正的,总体目标在子问题目标中是单调的,这允许动态规划。

def optimal_order(predecessors_map, weight_map):
    vertices = frozenset(predecessors_map.keys())
    memo_map = {frozenset(): (0, [])}
    return optimal_order_helper(predecessors_map, weight_map, vertices, memo_map)


def optimal_order_helper(predecessors_map, weight_map, vertices, memo_map):
    if vertices in memo_map:
        return memo_map[vertices]
    possibilities = []
    for v in vertices:
        if any(u in vertices for u in predecessors_map[v]):
            continue
        sub_obj, sub_order = optimal_order_helper(predecessors_map, weight_map, vertices - frozenset({v}), memo_map)
        possibilities.append((weight_map[v] * (1.0 + sub_obj), [v] + sub_order))
    best = min(possibilities)
    memo_map[vertices] = best
    return best


print(optimal_order({'u': [], 'v': ['u'], 'w': [], 'x': ['w']}, {'u': 1.2, 'v': 0.5, 'w': 1.1, 'x': 1.001}))

【讨论】:

  • 聪明,优秀!!你帮助我了解问题的性质和背景。
猜你喜欢
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多