/Bipartite.pm
https://github.com/gitpan/Graph-Bipartite · Perl · 206 lines · 163 code · 34 blank · 9 comment · 47 complexity · 9477056ef4616a5c63620c009781e51f MD5 · raw file
- package Graph::Bipartite;
- # $Id: Bipartite.pm,v 1.1 2003/05/25 15:03:20 detzold Exp $
- require 5.005_62;
- use strict;
- use warnings;
- require Exporter;
- our @ISA = qw(Exporter);
- # Items to export into callers namespace by default. Note: do not export
- # names by default without a very good reason. Use EXPORT_OK instead.
- # Do not simply export all your public functions/methods/constants.
- # This allows declaration use Graph::Bipartite ':all';
- # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
- # will save memory.
- our %EXPORT_TAGS = ( 'all' => [ qw(
-
- ) ] );
- our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
- our @EXPORT = qw(
-
- );
- our $VERSION = '0.01';
- # Preloaded methods go here.
- my $n1;
- my $n2;
- my $n;
- my @neighbours;
- sub new {
- $n1 = $_[ 1 ];
- $n2 = $_[ 2 ];
- $n = $n1 + $n2;
- for( my $i = 0; $i < $n; $i++ ) {
- $neighbours[ $i ] = [];
- }
- my $class = shift;
- my $self = { };
- bless( $self, $class );
- return $self;
- }
- sub insert_edge {
- push( @{ $neighbours[ $_[ 1 ] ] }, $_[ 2 ] );
- push( @{ $neighbours[ $_[ 2 ] ] }, $_[ 1 ] );
- }
- sub neighbours {
- if( scalar( @{ $neighbours[ $_[ 1 ] ] } ) > 0 ) {
- return scalar( @{ $neighbours[ $_[ 1 ] ] } );
- }
- 0;
- }
- my @matching;
- sub maximum_matching {
- for( my $i = 0; $i < $n; ++$i ) {
- $matching[ $i ] = -1;
- }
- while( _sbfs() > 0 ) {
- _sdfs();
- }
- my %h;
- for( my $i = 0; $i < $n1; ++$i ) {
- if( $matching[ $i ] != -1 ) {
- $h{ $i } = $matching[ $i ];
- }
- }
- %h;
- }
- my @level;
- sub _sbfs {
- my @queue1;
- my @queue2;
- for( my $i = 0; $i < $n1; ++$i ) {
- if( $matching[ $i ] == -1 ) {
- $level[ $i ] = 0;
- push( @queue1, $i );
- } else {
- $level[ $i ] = -1;
- }
- }
- for( my $i = $n1; $i < $n; ++$i ) {
- $level[ $i ] = -1;
- }
- while( scalar( @queue1 ) > 0 ) {
- $#queue2 = -1;
- my $free = 0;
- while( scalar( @queue1 ) > 0 ) {
- my $v = pop( @queue1 );
- for my $w ( @{ $neighbours[ $v ] } ) {
- if( $matching[ $v ] != $w && $level[ $w ] == -1 ) {
- $level[ $w ] = $level[ $v ] + 1;
- push( @queue2, $w );
- if( $matching[ $w ] == -1 ) {
- $free = $w;
- }
- }
- }
- }
- if( $free > 0 ) {
- return 1;
- }
- $#queue1 = -1;
- while( scalar( @queue2 ) > 0 ) {
- my $v = pop( @queue2 );
- for my $w ( @{ $neighbours[ $v ] } ) {
- if( $matching[ $v ] == $w && $level[ $w ] == -1 ) {
- $level[ $w ] = $level[ $v ] + 1;
- push( @queue1, $w );
- }
- }
- }
- }
- 0;
- }
- sub _sdfs {
- for( my $i = 0; $i < $n1; ++$i ) {
- if( $matching[ $i ] == -1 ) {
- _rec_sdfs( $i );
- }
- }
- }
- sub _rec_sdfs {
- my $u = $_[ 0 ];
- if( $u < $n1 ) {
- for my $w ( @{ $neighbours[ $u ] } ) {
- if( $matching[ $u ] != $w && $level[ $w ] == $level[ $u ] + 1 ) {
- if( _rec_sdfs( $w ) == 1 ) {
- $matching[ $u ] = $w;
- $matching[ $w ] = $u;
- $level[ $u ] = -1;
- return 1;
- }
- }
- }
- } else {
- if( $matching[ $u ] == -1 ) {
- $level[ $u ] = -1;
- return 1;
- } else {
- for my $w ( @{ $neighbours[ $u ] } ) {
- if( $matching[ $u ] == $w && $level[ $w ] == $level[ $u ] + 1 ) {
- if( _rec_sdfs( $w ) == 1 ) {
- $level[ $u ] = -1;
- return 1;
- }
- }
- }
- }
- }
- $level[ $u ] = -1;
- 0;
- }
- 1;
- __END__
- # Below is stub documentation for your module. You better edit it!
- =head1 NAME
- Graph::Bipartite - Graph algorithms on bipartite graphs.
- =head1 SYNOPSIS
- use Graph::Bipartite;
- $g = Graph::Bipartite->new( 5, 4 );
- $g->insert_edge( 3, 5 );
- $g->insert_edge( 2, 7 );
- %h = $g->maximum_matching();
- =head1 DESCRIPTION
- This algorithm computes the maximum matching of a bipartite unweighted
- and undirected graph in worst case running time O( sqrt(|V|) * |E| ).
- The constructor takes as first argument the number of vertices of the
- first partition V1, as second argument the number of vertices of the
- second partition V2. For nodes of the first partition the valid range
- is [0..|V1|-1], for nodes of the second partition it is [|V1|..|V1|+|V2|-1].
- The function maximum_matching() returns a maximum matching as a hash
- where the keys represents the vertices of V1 and the value of each
- key an edge to a vertex in V2 being in the matching.
- =head1 AUTHOR
- Daniel Etzold, detzold@gmx.de
- =head1 SEE ALSO
- perl(1).
- =cut