我试图找出在无向图中找到桥的切割顶点的最佳方法。我应该使用dfs吗?如果是这样我怎么去确定它是否是一座桥?我知道如何在纸上做,但不在代码中。
答案 0 :(得分:1)
我不认为你可以从知道切割顶点的任何好处来确定桥梁是什么。
图形可以没有切割顶点但仍然是桥梁:
即使两个切割顶点之间的边缘也不能保证成为桥梁:
桥是那些不在循环中的边缘。
您可以在图中使用深度优先搜索(DFS)从图中任意选择的节点中找到周期:
每当遇到已访问过的节点时,您就找到了一个循环。我们可以将此节点称为"循环"节点。此循环节点必须位于从起始节点后跟DFS的当前路径上。
将此循环的所有边标记为循环。或者,或者不是桥梁。该标记可以在DFS的回溯部分期间完成。如果"周期"节点仍在路径上方,标记当前边缘。一旦我们进一步向后回溯比访问的节点,就不再执行该标记。
在回溯到循环节点之前,我们可以找到几个循环:我们可以有几个循环节点待定,但只需要记住路径中最高的循环节点。为此,我们可以存储"深度"这样的循环节点在DFS搜索路径中具有。
这是执行DFS并识别网桥的伪代码:
visited = new Map # keyed by vertices, giving depth at which a vertext was visited
bridges = new Set(edges) # collection of all edges
func dfs(previous, current, depth):
visited.set(current, depth)
cycleParent = depth + 1 # This means: no cycle detected
for edge in edgesFrom(current):
next = nodesOnEdge(edge)[0] # get one vertex on this edge
if next == current: next = nodesOnEdge(edge)[1] # take the other vertex
if next != previous: # Not yet visited this edge
# Either already visited this node, or recursion is initiated
cycle = visited.get(next)
if not cycle: cyle = dfs(current, next, depth+1)
if cycle <= depth: bridges.remove(edge) # Edge is on a cycle
if cycle < cycleParent: cycleParent = cycle
return cycleParent
dfs(null, nodes[0], 1) # Start from any node, and depth = 1
# At the end of this process: bridges contains the answer.
根据您拥有的数据结构,您必须实现两个功能:
edgesFrom(node)
:返回入射到给定顶点的边nodesOnEdge(edge)
:返回由给定边连接的两个顶点(作为数组)。这是JavaScript中的一个实现,只是为了演示一个例子:
function getBridges(graph) {
const visited = new Map,
bridges = new Set(graph.edges().toArray());
function dfs(previous, current, depth) {
visited.set(current, depth);
let cycleParent = depth+1; // = No cycle
for (let edge of current.connectedEdges().toArray()) {
// Get other node on this edge
const next = edge.source() === current ? edge.target() : edge.source();
if (next === previous) continue; // Already visited this edge
// Either already visited this node, or recursion is initiated
const cycle = visited.get(next) || dfs(current, next, depth+1);
if (cycle <= depth) bridges.delete(edge); // Edge is on a cycle
if (cycle < cycleParent) cycleParent = cycle;
}
return cycleParent;
}
dfs(null, graph.nodes()[0], 1);
return bridges;
}
function pairsToGraph(pairs) {
// Initialise Cytoscape
const cy = cytoscape({ container: document.getElementById('cy') });
// Add points and edges to graph
cy.add(Array.from(new Set([].concat(...pairs)), id => ({data:{id}})));
cy.add(pairs.map(pair => ({data:{id: pair.join('_'), source: pair[0], target: pair[1]}})));
// Render graph
cy.layout({ name: 'cola', animate: true }).run();
return cy;
}
// Define graph
const pairs = [
[0,1], [1,2], [2,3], [3,1], [3,4], [4,5], [5,6], [6,3],
[6,7], [7,3], [7,8], [8,9], [9,10], [10,11], [11,12], [12,9],
[8,13], [13,14], [14,15], [15,16], [16,14], [16,13]
];
// Use cytoscape for creating a graph object and its rendering
const cy = pairsToGraph(pairs);
// Get the bridges, and highlight them
const bridges = getBridges(cy);
for (const bridge of bridges) bridge.select();
&#13;
#cy {
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.8/cytoscape.min.js"></script>
<script src="http://marvl.infotech.monash.edu/webcola/cola.v3.min.js"></script>
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-cola/2.0.0/cytoscape-cola.js"></script>
<div id="cy"></div>
&#13;