Re: [QUIZ] Perl 'Medium' Quiz: Graph Connected Components (#2006-12-29)
Shlomi Fish <shlomif-ik1l9ssToec+JF/[email protected]> Thu, 4 Jan 2007 16:55:38 +0200
| Newsgroups | gmane.comp.lang.perl.qotw.discuss |
|---|---|
| Message-ID | <[email protected]> |
On Thursday 04 January 2007 05:08, Julien Quint (Pom) wrote:
> On Dec 30, 2006, at 4:41 , Shlomi Fish wrote:
> > Here's a quiz for the new year. My sister received this challenge
> > for her
> > college homework, and had to write some Standard ML code to solve
> > it, a task
> > which I helped her with. I hope you enjoy it too.
>
> Hi all,
>
> here is my answer for this quizz. Nothing fancy, not thoroughly
> tested but this is a well-known solution.
>
Hi Julien!
Thanks for your solution. It compiles under "use strict" and "use warnings"
and passes all my tests. I also think it's much shorter than mine. :-).
I'm going to post my solution along with my tests later.
Regards,
Shlomi Fish
> # Compute the connected components of the graph and return a list of
> list of
> # edges. Every list is a connected components. The edges are ordered
> in the
> # same way as in the original list of edges.
> # A simple algorithm for computing connected components is to build the
> # equivalence classes of vertices in the graph. Vertices belonging to
> the
> # same component are equivalent and belong in the same class. A
> simple way
> # to represent equivalence classes is a Union-Find tree. All elements
> in a
> # tree are equivalent, and the tree structure makes it easy to build the
> # union of two equivalence classes as we just need to attach the root
> of one
> # the trees to any node in the other.
> # The algorithm works in three steps:
> # 1. Make a new tree for every vertex in the graph with this vertex
> as the
> # root (and only node so far.) Nodes point to their parent in a UF
> tree
> # and the root points to itself.
> # 2. An edge between two vertices u and v means that u and v are in
> the
> # same component, so u and v are equivalent, which means that all
> vertices
> # equivalent to u are equivalent to all vertices equivalent to u.
> This is
> # the union of their equivalent classes, which is implemented by
> attaching
> # the root of v's tree to u. Once we have iterated over every edge
> in the
> # graph, the resulting UF forest gives us the equivalence classes of
> # vertices.
> # 3. We build the list of list of edges (each list being a
> component) by
> # going through the original list of edges (to maintain the original
> # order) and finding which component the edge belongs to. For every
> edge,
> # looking up the root of the UF tree that one of its vertex belongs to
> # gives us the index of the component in the list of list of edges,
> and we
> # just push that vertex into the list.
> # Since we get the list of edges for the graph and not a list of
> vertices,
> # steps 1 and 2 can be merged.
> sub connected
> {
> my $edges = shift;
> # Step 1: initialize the UF forest for every vertex in the graph.
> my $uf = { map { map { $_ => $_ } @$_ } @$edges };
> # Step 2: make the union of the vertices of every edge.
> $uf->{root($uf, $_->[1])} = $_->[0] for @$edges;
> # Step 3: build the list of components. @components is the list
> itself,
> # %components is the mapping between the root of an UF-tree and
> the index
> # of the edge list in @components.
> my @components = ();
> my %components = ();
> for (@$edges) {
> my $root = root($uf, $_->[0]);
> $components{$root} = @components if !exists $components{$root};
> push @{$components[$components{$root}]}, $_;
> }
> return \@components;
> }
>
> # Find the root of an UF tree for a given node. We use a simple path
> # compression technique which also brings up nodes that we look-up
> closer to
> # the root.
> sub root
> {
> my ($uf, $u) = @_;
> while ($uf->{$u} != $u) {
> my $next = $uf->{$u};
> $uf->{$u} = $uf->{$next};
> $u = $next;
> }
> return $u;
> }
>
> Julien
--
---------------------------------------------------------------------
Shlomi Fish shlomif-ik1l9ssToec+JF/[email protected]
Homepage: http://www.shlomifish.org/
Chuck Norris wrote a complete Perl 6 implementation in a day but then
destroyed all evidence with his bare hands, so no one will know his secrets.