我只给了一组边,并询问图中是否有一个循环(图可能没有连接)。我知道使用简单的DFS可以很容易地解决它。但我想知道是否有任何其他方法降低了复杂性,因为我可能会收到多个此类查询以检查周期并且每次运行dfs都会产生O(nq)复杂度,n个边数和q个查询数。 / p>
答案 0 :(得分:2)
您可以使用不相交集,它可以找到O(E)
中的所有周期(E是边数)
它的作用:
跟踪直接或间接连接的节点 (意思是两个节点在同一组中)。
将两个节点放在同一个集合中。 (意思是他们 连接的)。实际上,它确实是这两个节点来自的两个集合的联合。
Disjoint set在O(1)
中执行这两项操作。
以下是我使用路径压缩实现Disjoint set的方法:
#include <iostream>
#include <cstdio>
using namespace std;
// This array is used to represent a backward tree (Forest actually)
// all nodes part of a tree are in the same set
int disjointset[1000];
// at first all nodes are separated
// that is they are part of a 1 element set
void initialize(int n){
for(int i= 0; i<=n; i++){
disjointset[i]= i;
}
}
// get the root parent of node a in disjoint tree structure
int getParent(int a){
if(disjointset[a] == a)
return a;
// we do this assignment to shorten the path from this node to it's top ancestor in tree
// this is called path compression
disjointset[a] = getParent(disjointset[a]);
return disjointset[a];
}
// check if two nodes are directly/indirectly connected
bool connected(int a, int b){
return getParent(a) == getParent(b);
}
// join two nodes a and b, after this they will be connected
void join(int a, int b){
disjointset[getParent(a)] = getParent(b);
}
int main(){
//freopen("F:/input.txt", "r", stdin);
// n nodes, e edges
int n, e, u, v;
cin>>n>>e; // e number of edges
//initialize the backward tree of disjoint set
initialize(n);
for(int i= 0; i<e; i++){
cin>>u>>v;
if(connected(u, v)){
cout<< "Cycle found"<<endl;
}
join(u,v);
}
}
/*
//sample input
//6 nodes 6 edges
6 6
1 2
2 3
1 3
3 4
3 5
4 6
*/
注意:多次插入相同的边将被视为一个循环。