我正在处理一个问题(来自Sedgewick的 Algorithms ,第4.1节,问题32)以帮助我理解,而且我不知道如何继续。
"并行边缘检测。设计一个线性时间算法来计算(多)图中的平行边。 提示:维护顶点邻居的布尔数组,并通过仅根据需要重新初始化条目来重用此数组。"
如果两条边连接同一对顶点,则认为它们是平行的
任何想法该怎么做?
答案 0 :(得分:1)
我认为我们可以使用BFS。
主要思想是能够判断是否告知两个节点之间是否存在两条或更多路径,因此我们可以使用一个集合来查看对应于节点的相邻列表的相邻节点是否已经在集合中
这使用O(n)额外空间但具有O(n)时间复杂度。 boolean bfs(int start){
Queue<Integer> q = new Queue<Integer>(); // get a Queue
boolean[] mark = new boolean[num_of_vertices];
mark[start] = true; // put 1st node into Queue
q.add(start);
while(!q.isEmpty()){
int current = q.remove();
HashSet<Integer> set = new HashSet<Integer>(); /* use a hashset for
storing nodes of current adj. list*/
ArrayList<Integer> adjacentlist= graph.get(current); // get adj. list
for(int x : adjacentlist){
if(set.contains(x){ // if it already had a edge current-->x
return true; // then we have our parallel edge
}
else set.add(x); // if not then we have a new edge
if(!marked[x]){ // normal bfs routine
mark[x]=true;
q.add(x);
}
}
}
}// assumed graph has ArrayList<ArrayList<Integer>> representation
// undirected
答案 1 :(得分:0)
假设图中的顶点是整数0 .. |V|
。
如果您的图表是定向的,则图表中的边缘表示为(i, j)
。
这允许您生成任何边缘到整数(散列函数)的唯一映射,该整数可以在O(1)中找到。
h(i, j) = i * |V| + j
您可以在分摊的O(1)时间内在哈希表中插入/查找元组(i, j)
。对于邻接列表中的|E|
个边,这意味着邻接列表中的边数将为总运行时间O(| E |)或线性。
这个的python实现可能如下所示:
def identify_parallel_edges(adj_list):
# O(n) list of edges to counts
# The Python implementation of tuple hashing implements a more sophisticated
# version of the approach described above, but is still O(1)
edges = {}
for edge in adj_list:
if edge not in edges:
edges[edge] = 0
edges[edge] += 1
# O(n) filter non-parallel edges
res = []
for edge, count in edges.iteritems():
if count > 1:
res.append(edge)
return res
edges = [(1,0),(2,1),(1,0),(3,4)]
print identify_parallel_edges(edges)
答案 2 :(得分:0)
我也在研究这个问题,请帮我检查一下我的想法是否正确。
似乎提示告诉我们,我们可以重用Cycle.java中的代码部分。 (https://algs4.cs.princeton.edu/41graph/Cycle.java.html)
// does this graph have two parallel edges?
// side effect: initialize cycle to be two parallel edges
private boolean hasParallelEdges(Graph G) {
marked = new boolean[G.V()];
for (int v = 0; v < G.V(); v++) {
// check for parallel edges incident to v
for (int w : G.adj(v)) {
if (marked[w]) {
cycle = new Stack<Integer>();
cycle.push(v);
cycle.push(w);
cycle.push(v);
return true;
}
marked[w] = true;
}
// reset so marked[v] = false for all v
for (int w : G.adj(v)) {
marked[w] = false;
}
}
return false;
}
正如提示告诉我们的那样,我们可以初始化由前一个顶点连接的条目,而不是初始化整个G.V()大小的数组。然后通过BFS对图中的每个顶点进行递归。因此,我们花费的时间应与BFS,O(V + E)处于同一水平,这是线性的。
// these shall be done in the constructor
count = 0;
marked = new boolean[G.V()];
// count the number of parallel edges
private boolean parallelEdges(Graph G, int v) {
for (int v = 0; v < G.V(); v++) {
// check for parallel edges incident to v
for (int w : G.adj(v)) {
if (marked[w]) {
count++; // the number of parallel edges
}
marked[w] = true;
}
// reset so marked[v] = false for all v
for (int w : G.adj(v)) {
marked[w] = false;
}
for (int w : G.adj(v)) {
markedForBFS[v] = true;
for (int w : G.adj(v))
if (!markedForBFS[v])
parallelEdges(G, w);
}
}
return false;
}
我认为关键是不要将两个标记的数组混合在一起。