在图或树中查找冗余边的算法

时间:2009-02-04 06:29:02

标签: algorithm language-agnostic tree graph-theory

是否有用于在图中查找冗余边的既定算法?

例如,我想找到a-> d和a-> e是多余的,然后摆脱它们,如下所示:

alt text => alt text

编辑:Strilanc非常善于为我读懂我的想法。 “冗余”太强了,因为在上面的例子中,a-> b或a-> c都不被认为是多余的,但a-> d是。

7 个答案:

答案 0 :(得分:26)

您想要计算维持顶点可达性的最小图。

这称为图表的transitive reduction。维基百科文章应该让你开始走正确的道路。

答案 1 :(得分:1)

给定图形的不包含“冗余边缘”的子图称为该图的“spanning tree”。对于任何给定的图形,可以使用多个生成树。

因此,为了摆脱冗余边缘,您需要做的就是找到图形的任何一个生成树。您可以使用任何depth-first-searchbreadth-first-search算法并继续搜索,直到您访问了图表中的每个顶点。

答案 2 :(得分:1)

请检查:Minimum Spanning Tree

答案 3 :(得分:1)

有几种攻击方法,但首先你需要更准确地定义问题。首先,你在这里的图表是非循环的和有针对性的:这总是真的吗?

接下来,您需要定义“冗余边缘”的含义。在这种情况下,您从一个图表开始,该图表有两条路径a-> c:一条经由b而另一条是直接的。由此我推断,通过“冗余”,你的意思是这样的。设 G =< V,E> 是一个图形, V 顶点的集合和E⊆V×V 边缘集合。有点看起来你要定义从 v i v j 的所有边缘都比最长边缘短“冗余”。所以最简单的方法是使用深度优先搜索,枚举路径,当你找到一个更长的新路径时,将其保存为最佳候选者。

但是,我无法想象你想要它做什么。你能告诉?

答案 4 :(得分:0)

我遇到了类似的问题,最终以这种方式解决了问题:

我的数据结构由dependends字典组成,从节点id到依赖它的节点列表(即DAG中的跟随者)。请注意,它仅适用于DAG - 即有向,非循环图。

我还没有计算出它的确切复杂程度,但它在瞬间吞噬了几千个图表。

_transitive_closure_cache = {}
def transitive_closure(self, node_id):
    """returns a set of all the nodes (ids) reachable from given node(_id)"""
    global _transitive_closure_cache
    if node_id in _transitive_closure_cache:
        return _transitive_closure_cache[node_id]
    c = set(d.id for d in dependents[node_id])
    for d in dependents[node_id]:
        c.update(transitive_closure(d.id))  # for the non-pythonists - update is update self to Union result
    _transitive_closure_cache[node_id] = c
    return c

def can_reduce(self, source_id, dest_id):
    """returns True if the edge (source_id, dest_id) is redundant (can reach from source_id to dest_id without it)"""
    for d in dependents[source_id]:
        if d.id == dest_id:
            continue
        if dest_id in transitive_closure(d.id):
            return True # the dest node can be reached in a less direct path, then this link is redundant
    return False

# Reduce redundant edges:
for node in nodes:      
    dependents[node.id] = [d for d in dependents[node.id] if not can_reduce(node.id, d.id)]

答案 5 :(得分:0)

由于@Craig提到的Wikipedia文章仅对实现起到了推波助澜的作用,因此我将实现与Java 8流一起发布:

Map<String, Set<String>> reduction = usages.entrySet().stream()
                .collect(toMap(
                        Entry::getKey,
                        (Entry<String, Set<String>> entry) -> {
                            String start = entry.getKey();
                            Set<String> neighbours = entry.getValue();
                            Set<String> visited = new HashSet<>();
                            Queue<String> queue = new LinkedList<>(neighbours);

                            while (!queue.isEmpty()) {
                                String node = queue.remove();
                                usages.getOrDefault(node, emptySet()).forEach(next -> {
                                    if (next.equals(start)) {
                                        throw new RuntimeException("Cycle detected!");
                                    }
                                    if (visited.add(next)) {
                                        queue.add(next);
                                    }
                                });
                            }

                            return neighbours.stream()
                                    .filter(s -> !visited.contains(s))
                                    .collect(toSet());
                        }
                ));

答案 6 :(得分:-1)

我认为最简单的方法,实际想象一下它在实际工作中的表现,想象一下你是否有关节,喜欢

(A-> B)(B-> C)(A-> C),想象一下近图之间的距离是否等于1,所以

(A-> B)= 1,(B-> C)= 1,(A-> C)= 2.

所以你可以移除关节(A-> C)。

换句话说,最小化。

这只是我的想法,我将在开始时考虑它。网上有各种文章和资料来源,你可以看看它们并深入了解。

资源,可以帮助您:

Algorithm for Removing Redundant Edges in the Dual Graph of a Non-Binary CSP

Graph Data Structure and Basic Graph Algorithms

Google Books, On finding minimal two connected Subgraphs

Graph Reduction

Redundant trees for preplanned recovery in arbitraryvertex-redundant or edge-redundant graphs