Ruby 验证和规范化偏序集
我有一个这样的成对数组:Ruby 验证和规范化偏序集,ruby,algorithm,tree,graph-algorithm,Ruby,Algorithm,Tree,Graph Algorithm,我有一个这样的成对数组: [["a", "b"], ["b", "d"], ["a", "c"], ["e", "d"], ["a", "d"], ..., ["s", "f"]] 检查给定数组是否可以表示偏序的有效方法是什么?也就是说,给定数组中没有[a,b]、[b,c]、[c,a]这样的循环 如果确定数组表示偏序,我想通过删除所有可以通过自反性或传递性派生的对来规范化它。例如,在上面的例子中,由于存在[a,b]和[b,d],所以对[a,d]是冗余的,并且应该被移除 1和2之间的顺序无关紧要
[["a", "b"], ["b", "d"], ["a", "c"], ["e", "d"], ["a", "d"], ..., ["s", "f"]]
检查给定数组是否可以表示偏序的有效方法是什么?也就是说,给定数组中没有[a,b]、[b,c]、[c,a]这样的循环
如果确定数组表示偏序,我想通过删除所有可以通过自反性或传递性派生的对来规范化它。例如,在上面的例子中,由于存在[a,b]和[b,d],所以对[a,d]是冗余的,并且应该被移除
1和2之间的顺序无关紧要。如果2应该在1之前或在1的过程中完成,那么就可以了
最好是我希望它在Ruby 1.9.3中,但只要伪代码就足够了。对于数字1:
你可以将你的问题模块化为a,每一对都是一条边,接下来你可以运行a——如果算法失败,图形不是a——并且有一个循环——否则——你得到一个可能的偏序,作为拓扑排序的输出
2号:
关于这一部分我一点也不确定,所以这个答案实际上只是部分的,很抱歉——但只是初步的想法:
您可以使用,并将边从已发现的顶点删除到刚刚发现的顶点[在同一路径上]。虽然我不认为它是最优的,但是迭代地进行预处理(直到不做任何更改)将改善它
2号的深度思考:
我不确定您在这里的意思,但是DFS创建的林满足了您的请求,但是我担心您使用它可能会丢失太多数据,例如:[a,b],[a,c],[b,d],[c,d]将修剪[b,d]或[c,d]中的一个,这可能太多,但它也会修剪所有冗余边,如示例中所述 对于数字1:
你可以将你的问题模块化为a,每一对都是一条边,接下来你可以运行a——如果算法失败,图形不是a——并且有一个循环——否则——你得到一个可能的偏序,作为拓扑排序的输出
2号:
关于这一部分我一点也不确定,所以这个答案实际上只是部分的,很抱歉——但只是初步的想法:
您可以使用,并将边从已发现的顶点删除到刚刚发现的顶点[在同一路径上]。虽然我不认为它是最优的,但是迭代地进行预处理(直到不做任何更改)将改善它
2号的深度思考:
我不确定您在这里的意思,但是DFS创建的林满足了您的请求,但是我担心您使用它可能会丢失太多数据,例如:[a,b],[a,c],[b,d],[c,d]将修剪[b,d]或[c,d]中的一个,这可能太多,但它也会修剪所有冗余边,如示例中所述 第二个问题被称为。第二个问题被称为。对于问题的第一部分,我在一个数学网站的帮助下得出了自己的答案 对于问题的第二部分,在遵循其他答案中给出的建议后,我在Ruby I中实现了使用公式R^-=R-R\cdot R^+计算传递闭包、ii组合和iii传递归约
module Digraph; module_function
def vertices graph; graph.flatten(1).uniq end
## Floyd-Warshall algorithm
def transitive_closure graph
vs = vertices(graph)
path = graph.inject({}){|path, e| path[e] = true; path}
vs.each{|k| vs.each{|i| vs.each{|j| path[[i, j]] ||= true if path[[i, k]] && path[[k, j]]}}}
path.keys
end
def compose graph1, graph2
vs = (vertices(graph1) + vertices(graph2)).uniq
path1 = graph1.inject({}){|path, e| path[e] = true; path}
path2 = graph2.inject({}){|path, e| path[e] = true; path}
path = {}
vs.each{|k| vs.each{|i| vs.each{|j| path[[i, j]] ||= true if path1[[i, k]] && path2[[k, j]]}}}
path.keys
end
def transitive_reduction graph
graph - compose(graph, transitive_closure(graph))
end
end
用法示例:
Digraph.transitive_closure([[1, 2], [2, 3], [3, 4]])
#=> [[1, 2], [2, 3], [3, 4], [1, 3], [1, 4], [2, 4]]
Digraph.compose([[1, 2], [2, 3]], [[2, 4], [3, 5]])
#=> [[1, 4], [2, 5]]
Digraph.transitive_reduction([[1, 2], [2, 3], [3, 4], [1, 3], [1, 4], [2, 4]])
#=> [[1, 2], [2, 3], [3, 4]]
对于问题的第一部分,我在数学网站的帮助下得出了自己的答案 对于问题的第二部分,在遵循其他答案中给出的建议后,我在Ruby I中实现了使用公式R^-=R-R\cdot R^+计算传递闭包、ii组合和iii传递归约
module Digraph; module_function
def vertices graph; graph.flatten(1).uniq end
## Floyd-Warshall algorithm
def transitive_closure graph
vs = vertices(graph)
path = graph.inject({}){|path, e| path[e] = true; path}
vs.each{|k| vs.each{|i| vs.each{|j| path[[i, j]] ||= true if path[[i, k]] && path[[k, j]]}}}
path.keys
end
def compose graph1, graph2
vs = (vertices(graph1) + vertices(graph2)).uniq
path1 = graph1.inject({}){|path, e| path[e] = true; path}
path2 = graph2.inject({}){|path, e| path[e] = true; path}
path = {}
vs.each{|k| vs.each{|i| vs.each{|j| path[[i, j]] ||= true if path1[[i, k]] && path2[[k, j]]}}}
path.keys
end
def transitive_reduction graph
graph - compose(graph, transitive_closure(graph))
end
end
用法示例:
Digraph.transitive_closure([[1, 2], [2, 3], [3, 4]])
#=> [[1, 2], [2, 3], [3, 4], [1, 3], [1, 4], [2, 4]]
Digraph.compose([[1, 2], [2, 3]], [[2, 4], [3, 5]])
#=> [[1, 4], [2, 5]]
Digraph.transitive_reduction([[1, 2], [2, 3], [3, 4], [1, 3], [1, 4], [2, 4]])
#=> [[1, 2], [2, 3], [3, 4]]
以你的[a,b],[a,c],[b,d],[c,d]为例,我不打算删减任何内容。如果,还有[a,d],那就必须删减。@sawa:这就是我所想的,正如我所说的,这只是部分答案——为第一部分提供了一个解决方案。[a,d]将使用标准DFS终止。然而,我认为初级thaught值得研究[它与深层thaught有点不同,因为它是在DFS运行期间迭代修剪边],而不是一次完成所有的解决方案。以你的[a,b],[a,c],[b,d],[c,d]为例,我不打算修剪任何东西。如果,还有[a,d],那就必须删减。@sawa:这就是我所想的,正如我所说的,这只是部分答案——为第一部分提供了一个解决方案。[a,d]将使用标准DFS终止。然而,我认为初级thaught值得研究[它与深层thaught有点不同,因为它是在DFS运行期间迭代修剪边],而不是一次解决所有问题。