Classical eulerian cycle algorithm: Difference between revisions

From Algowiki
Jump to navigation Jump to search
 
(11 intermediate revisions by 3 users not shown)
Line 1: Line 1:
[[File:Nikolaus.png|200px|thumb|right|Another may well know example with 44 solutions]]
[[File:Nikolaus.png|400px|thumb|right|Another may well know example with 44 solutions]]


== General information ==
== General information ==
Line 7: Line 7:
''' Type of algorithm:''' recursion with an arbitrarily chosen start node <math>s\in V</math> as an additional input. Before the proper recursive procedure is invoked, the output sequence <math>S</math> is initialized so as to contain the start node <math>s</math> and nothing else.
''' Type of algorithm:''' recursion with an arbitrarily chosen start node <math>s\in V</math> as an additional input. Before the proper recursive procedure is invoked, the output sequence <math>S</math> is initialized so as to contain the start node <math>s</math> and nothing else.


'''Break condition:''' No edges/arcs leave the start node <math>s</math>.
== Recursion anchor ==


== Induction basis ==
No edges/arcs leave the start node <math>s</math> of that recursive call.


'''Abstract view:''' Nothing to do.
== Recursive step ==


== Induction step ==
For notational convenience, both undirected edges and directed arcs are denoted by parentheses in the following (in the direction in which they are looked at).
 
For notational convenience, both undirected edges and directed arcs are denoted by parentheses in the following.


# Let <math>p</math> be a (dynamically growing) path, represented in <math>p</math> as an alternating sequence of nodes and edges/arcs.
# Let <math>p</math> be a (dynamically growing) path, represented in <math>p</math> as an alternating sequence of nodes and edges/arcs.
Line 25: Line 23:
## Append <math>(x,y)</math> and then <math>y</math> to <math>p</math>.
## Append <math>(x,y)</math> and then <math>y</math> to <math>p</math>.
## Set <math>x:=y</math>.
## Set <math>x:=y</math>.
# If <math>x\neq s</math>, terminate the algorithm with the statement that no Eulerian cycle exists.
# If <math>x\neq s</math>, terminate the algorithm with the statement that no eulerian cycle exists.
# Otherwise: For each node <math>v</math> on <math>p</math> that still has leaving edges/arcs,:
# Otherwise: For each node <math>v</math> on <math>p</math> that still has leaving edges/arcs,:
## Call the procedure recursively with <math>v</math> as the start node, giving path <math>p'</math>.
## Call the procedure recursively with <math>v</math> as the start node, giving path <math>p'</math>.
Line 32: Line 30:
== Correctness ==
== Correctness ==


Since each edge/arc is removed immediately when it is processed, no edge/arc occurs twice in the output. Obviously, steps 4.3 and 6.2 ensure that the order in which the nodes and edges/arcs occur in the output yields a correct path. Obviously, whenever step 4 is finished, it is <math>x=s</math> and the remaining graph is Eulerian, if the original graph was Eulerian. Consequently, the statement that no Eulerian cycle exists is only delivered if true, and the graph handed over to a recursive call is Eulerian, if the original graph was Eulerian.
Since each edge/arc is removed immediately when it is processed, no edge/arc occurs twice in the output. Obviously, steps 4.3 and 6.2 ensure that the order in which the nodes and edges/arcs occur in the output yields a correct path. Obviously, whenever step 4 is finished, it is <math>x=s</math> and the remaining graph is eulerian, if the original graph was eulerian. Consequently, the statement that no eulerian cycle exists is only delivered in step 5 if the graph is indeed non-eulerian. Moreover, the graph handed over to a recursive call is Eulerian, if the original graph was Eulerian.


Suppose for a contradiction that some edge/arc <math>e/a</math> is '''not''' in the output. Since the graph is (strongly) connected, there is a path <math>q</math> from the start node to the tail of <math>e/a</math> (an arbitrary endnode of <math>e/a</math> in the undirected case). Let <math>v</math> be the last node on <math>q</math> processed by any recursive call. Then the subsequent edge/arc on <math>q</math> has not been processed, which contradicts the procedure.
Suppose for a contradiction that some edge/arc <math>e/a</math> is '''not''' in the output. Since the graph is (strongly) connected, there is a path <math>q</math> from the start node of the algorithm to the beginning node of <math>a</math> (an arbitrary endnode of <math>e</math> in the undirected case). Let <math>v</math> be the last node on <math>q</math> processed by any recursive call. Then the subsequent edge/arc on <math>q</math> has not been processed, which contradicts the procedure.


== Complexity ==
== Complexity ==

Latest revision as of 08:15, 2 November 2015

Another may well know example with 44 solutions

General information

Algorithmic problem: Eulerian cycle

Type of algorithm: recursion with an arbitrarily chosen start node [math]\displaystyle{ s\in V }[/math] as an additional input. Before the proper recursive procedure is invoked, the output sequence [math]\displaystyle{ S }[/math] is initialized so as to contain the start node [math]\displaystyle{ s }[/math] and nothing else.

Recursion anchor

No edges/arcs leave the start node [math]\displaystyle{ s }[/math] of that recursive call.

Recursive step

For notational convenience, both undirected edges and directed arcs are denoted by parentheses in the following (in the direction in which they are looked at).

  1. Let [math]\displaystyle{ p }[/math] be a (dynamically growing) path, represented in [math]\displaystyle{ p }[/math] as an alternating sequence of nodes and edges/arcs.
  2. Initialize [math]\displaystyle{ p }[/math] so as to contain [math]\displaystyle{ s }[/math] and nothing else.
  3. Set [math]\displaystyle{ x:=s }[/math].
  4. While there are edges/arcs leaving [math]\displaystyle{ x }[/math]:
    1. Choose one such arc [math]\displaystyle{ (x,y) }[/math].
    2. Remove [math]\displaystyle{ (x,y) }[/math] from the graph.
    3. Append [math]\displaystyle{ (x,y) }[/math] and then [math]\displaystyle{ y }[/math] to [math]\displaystyle{ p }[/math].
    4. Set [math]\displaystyle{ x:=y }[/math].
  5. If [math]\displaystyle{ x\neq s }[/math], terminate the algorithm with the statement that no eulerian cycle exists.
  6. Otherwise: For each node [math]\displaystyle{ v }[/math] on [math]\displaystyle{ p }[/math] that still has leaving edges/arcs,:
    1. Call the procedure recursively with [math]\displaystyle{ v }[/math] as the start node, giving path [math]\displaystyle{ p' }[/math].
    2. Replace [math]\displaystyle{ v }[/math] in [math]\displaystyle{ p }[/math] by [math]\displaystyle{ p' }[/math].

Correctness

Since each edge/arc is removed immediately when it is processed, no edge/arc occurs twice in the output. Obviously, steps 4.3 and 6.2 ensure that the order in which the nodes and edges/arcs occur in the output yields a correct path. Obviously, whenever step 4 is finished, it is [math]\displaystyle{ x=s }[/math] and the remaining graph is eulerian, if the original graph was eulerian. Consequently, the statement that no eulerian cycle exists is only delivered in step 5 if the graph is indeed non-eulerian. Moreover, the graph handed over to a recursive call is Eulerian, if the original graph was Eulerian.

Suppose for a contradiction that some edge/arc [math]\displaystyle{ e/a }[/math] is not in the output. Since the graph is (strongly) connected, there is a path [math]\displaystyle{ q }[/math] from the start node of the algorithm to the beginning node of [math]\displaystyle{ a }[/math] (an arbitrary endnode of [math]\displaystyle{ e }[/math] in the undirected case). Let [math]\displaystyle{ v }[/math] be the last node on [math]\displaystyle{ q }[/math] processed by any recursive call. Then the subsequent edge/arc on [math]\displaystyle{ q }[/math] has not been processed, which contradicts the procedure.

Complexity

Statement: Both for directed and undirected graphs, the asymtptotic complexity is linear in the number of edges/ars.

Proof: We assume that all data structures are implemented in the obvious appropriate way. First note that steps 1, 2, 3, and 5 take constant time each. So the total complexity of these steps is linear in the number of recursive calls, which is linear in the number of edges/arcs in turn. The total number of iterations of steps 4 and 6, respectively, taken over all recursive calls, is linear in the number of edges/arcs as well.

Remarks:

  1. Since the graph is (strongly) connected, the number of nodes is asymptotically dominated by the number of edges/arcs and, therefore, irrelevant here.
  2. Of course, the edges/arcs need not be removed permanently. However, when an edge/arc is processed, it must be hidden from the algorithm up to its termination to achieve the linear bound on the complexity. A boolean edge/arc label to indicate whether this edge/arc has already been processed, does not suffice.

Example