/Bipartite.pm

https://github.com/gitpan/Graph-Bipartite · Perl · 206 lines · 163 code · 34 blank · 9 comment · 47 complexity · 9477056ef4616a5c63620c009781e51f MD5 · raw file

  1. package Graph::Bipartite;
  2. # $Id: Bipartite.pm,v 1.1 2003/05/25 15:03:20 detzold Exp $
  3. require 5.005_62;
  4. use strict;
  5. use warnings;
  6. require Exporter;
  7. our @ISA = qw(Exporter);
  8. # Items to export into callers namespace by default. Note: do not export
  9. # names by default without a very good reason. Use EXPORT_OK instead.
  10. # Do not simply export all your public functions/methods/constants.
  11. # This allows declaration use Graph::Bipartite ':all';
  12. # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
  13. # will save memory.
  14. our %EXPORT_TAGS = ( 'all' => [ qw(
  15. ) ] );
  16. our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
  17. our @EXPORT = qw(
  18. );
  19. our $VERSION = '0.01';
  20. # Preloaded methods go here.
  21. my $n1;
  22. my $n2;
  23. my $n;
  24. my @neighbours;
  25. sub new {
  26. $n1 = $_[ 1 ];
  27. $n2 = $_[ 2 ];
  28. $n = $n1 + $n2;
  29. for( my $i = 0; $i < $n; $i++ ) {
  30. $neighbours[ $i ] = [];
  31. }
  32. my $class = shift;
  33. my $self = { };
  34. bless( $self, $class );
  35. return $self;
  36. }
  37. sub insert_edge {
  38. push( @{ $neighbours[ $_[ 1 ] ] }, $_[ 2 ] );
  39. push( @{ $neighbours[ $_[ 2 ] ] }, $_[ 1 ] );
  40. }
  41. sub neighbours {
  42. if( scalar( @{ $neighbours[ $_[ 1 ] ] } ) > 0 ) {
  43. return scalar( @{ $neighbours[ $_[ 1 ] ] } );
  44. }
  45. 0;
  46. }
  47. my @matching;
  48. sub maximum_matching {
  49. for( my $i = 0; $i < $n; ++$i ) {
  50. $matching[ $i ] = -1;
  51. }
  52. while( _sbfs() > 0 ) {
  53. _sdfs();
  54. }
  55. my %h;
  56. for( my $i = 0; $i < $n1; ++$i ) {
  57. if( $matching[ $i ] != -1 ) {
  58. $h{ $i } = $matching[ $i ];
  59. }
  60. }
  61. %h;
  62. }
  63. my @level;
  64. sub _sbfs {
  65. my @queue1;
  66. my @queue2;
  67. for( my $i = 0; $i < $n1; ++$i ) {
  68. if( $matching[ $i ] == -1 ) {
  69. $level[ $i ] = 0;
  70. push( @queue1, $i );
  71. } else {
  72. $level[ $i ] = -1;
  73. }
  74. }
  75. for( my $i = $n1; $i < $n; ++$i ) {
  76. $level[ $i ] = -1;
  77. }
  78. while( scalar( @queue1 ) > 0 ) {
  79. $#queue2 = -1;
  80. my $free = 0;
  81. while( scalar( @queue1 ) > 0 ) {
  82. my $v = pop( @queue1 );
  83. for my $w ( @{ $neighbours[ $v ] } ) {
  84. if( $matching[ $v ] != $w && $level[ $w ] == -1 ) {
  85. $level[ $w ] = $level[ $v ] + 1;
  86. push( @queue2, $w );
  87. if( $matching[ $w ] == -1 ) {
  88. $free = $w;
  89. }
  90. }
  91. }
  92. }
  93. if( $free > 0 ) {
  94. return 1;
  95. }
  96. $#queue1 = -1;
  97. while( scalar( @queue2 ) > 0 ) {
  98. my $v = pop( @queue2 );
  99. for my $w ( @{ $neighbours[ $v ] } ) {
  100. if( $matching[ $v ] == $w && $level[ $w ] == -1 ) {
  101. $level[ $w ] = $level[ $v ] + 1;
  102. push( @queue1, $w );
  103. }
  104. }
  105. }
  106. }
  107. 0;
  108. }
  109. sub _sdfs {
  110. for( my $i = 0; $i < $n1; ++$i ) {
  111. if( $matching[ $i ] == -1 ) {
  112. _rec_sdfs( $i );
  113. }
  114. }
  115. }
  116. sub _rec_sdfs {
  117. my $u = $_[ 0 ];
  118. if( $u < $n1 ) {
  119. for my $w ( @{ $neighbours[ $u ] } ) {
  120. if( $matching[ $u ] != $w && $level[ $w ] == $level[ $u ] + 1 ) {
  121. if( _rec_sdfs( $w ) == 1 ) {
  122. $matching[ $u ] = $w;
  123. $matching[ $w ] = $u;
  124. $level[ $u ] = -1;
  125. return 1;
  126. }
  127. }
  128. }
  129. } else {
  130. if( $matching[ $u ] == -1 ) {
  131. $level[ $u ] = -1;
  132. return 1;
  133. } else {
  134. for my $w ( @{ $neighbours[ $u ] } ) {
  135. if( $matching[ $u ] == $w && $level[ $w ] == $level[ $u ] + 1 ) {
  136. if( _rec_sdfs( $w ) == 1 ) {
  137. $level[ $u ] = -1;
  138. return 1;
  139. }
  140. }
  141. }
  142. }
  143. }
  144. $level[ $u ] = -1;
  145. 0;
  146. }
  147. 1;
  148. __END__
  149. # Below is stub documentation for your module. You better edit it!
  150. =head1 NAME
  151. Graph::Bipartite - Graph algorithms on bipartite graphs.
  152. =head1 SYNOPSIS
  153. use Graph::Bipartite;
  154. $g = Graph::Bipartite->new( 5, 4 );
  155. $g->insert_edge( 3, 5 );
  156. $g->insert_edge( 2, 7 );
  157. %h = $g->maximum_matching();
  158. =head1 DESCRIPTION
  159. This algorithm computes the maximum matching of a bipartite unweighted
  160. and undirected graph in worst case running time O( sqrt(|V|) * |E| ).
  161. The constructor takes as first argument the number of vertices of the
  162. first partition V1, as second argument the number of vertices of the
  163. second partition V2. For nodes of the first partition the valid range
  164. is [0..|V1|-1], for nodes of the second partition it is [|V1|..|V1|+|V2|-1].
  165. The function maximum_matching() returns a maximum matching as a hash
  166. where the keys represents the vertices of V1 and the value of each
  167. key an edge to a vertex in V2 being in the matching.
  168. =head1 AUTHOR
  169. Daniel Etzold, detzold@gmx.de
  170. =head1 SEE ALSO
  171. perl(1).
  172. =cut