如果任何节点最多有2个边缘,可以更快地找出是否形成循环?

时间:2011-07-04 14:01:10

标签: algorithm cycle

首先,没有作业。


问题在于:

An undirected unweighted graph has N nodes.
Any node can have at most 2 edges to different nodes.
I need to know whether at least a cycle is formed.

输入:

M pairs of integers, as edges.
There can be duplicates, like "2 3" and "3 2".
The data may be invalid, for example: "1 2" "1 3" "1 4". The program needs to detect this.

我的方法(太慢):

0.1) A set for edges to detect duplicates. (C++ e.g.: std::set<int>)
0.2) A map for nodes to count how many edges from each node. (std::map<int,int>)
0.3) A list for links. A link is a set of connected nodes. (std::list<std::set<int> >)

1) Read in an edge, and change the edge to ascending order, e.g.: "3 2" -> "2 3".

2.1) If the edge has already be "drawn", skip and go to 1);
2.2) If either vertex has already got 2 edges, invalid! 
2.3) Otherwise, check whether either of the nodes has already been in a link.

3.1) If neither, create a new link and add to the list.
3.2) If only one, add the single one to the link.
3.3) If both,
3.3.1) If in the same link, a cycle has been formed!
3.3.2) If not, merge two links.

请推荐更快的算法,以及算法的数据结构。谢谢。

3 个答案:

答案 0 :(得分:2)

无向图的标准算法是在其上运行depth first search,跟踪当前路径上的节点。如果您遇到受访节点,那么您就有了一个循环。

答案 1 :(得分:1)

由于每个节点最多有2个入射边,因此删除任何具有0个边的节点,然后重复删除任何只有一个入射边(以及相应边)的节点。如果你有一个循环,你将到达一个没有可以移除的节点的阶段,但仍然会有节点。如果没有循环,那么您将终止删除所有节点。

编辑:处理可能无效的输入,并更明确地了解基础数据结构。

在构建数据结构时读取数据,该数据结构由节点ID索引,并且对于每个索引条目,包含事件到该节点的节点列表。 [即当读入每个边时,有两个条目要做,每个节点一个。]当数据进入时,删除重复项并发现是否有任何节点入射到太多边缘。这是线性的。

保留具有单个事件边缘的节点列表。在算法的每一步中,您从此列表中选择任何节点,并删除边缘,将其链接的节点放入此列表中(如有必要)。 [如果节点已经在列表中,您可以将其删除或修改上一步骤,只是忽略从列表中获取的没有更多事件边缘的任何边缘。]

边缘最多添加一次到列表中,每次迭代都会从该列表中删除一条边。因此是线性的。

答案 2 :(得分:0)

您可以选择Prim或Kruskal的算法来创建最短的生成树。基本上,他们都试图在没有创建电路的情况下向新树添加最小重量的边缘。您只需稍微修改算法,以便在创建电路的情况下,您只需中断该过程。

如果我记得正确(e:边缘),它们都以O(e log e)运行,但它可能会更快,因为你可以很早就打破。