File Coverage

blib/lib/Graph/Bipartite.pm
Criterion Covered Total %
statement 6 88 6.8
branch 0 28 0.0
condition 0 12 0.0
subroutine 2 9 22.2
pod 0 4 0.0
total 8 141 5.6


line stmt bran cond sub pod time code
1             package Graph::Bipartite;
2             # $Id: Bipartite.pm,v 1.1 2003/05/25 15:03:20 detzold Exp $
3              
4             require 5.005_62;
5 1     1   713 use strict;
  1         2  
  1         42  
6 1     1   6 use warnings;
  1         2  
  1         1176  
7              
8             require Exporter;
9              
10             our @ISA = qw(Exporter);
11              
12             # Items to export into callers namespace by default. Note: do not export
13             # names by default without a very good reason. Use EXPORT_OK instead.
14             # Do not simply export all your public functions/methods/constants.
15              
16             # This allows declaration use Graph::Bipartite ':all';
17             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
18             # will save memory.
19             our %EXPORT_TAGS = ( 'all' => [ qw(
20            
21             ) ] );
22              
23             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
24              
25             our @EXPORT = qw(
26            
27             );
28             our $VERSION = '0.01';
29              
30              
31             # Preloaded methods go here.
32             my $n1;
33             my $n2;
34             my $n;
35             my @neighbours;
36              
37             sub new {
38 0     0 0   $n1 = $_[ 1 ];
39 0           $n2 = $_[ 2 ];
40 0           $n = $n1 + $n2;
41 0           for( my $i = 0; $i < $n; $i++ ) {
42 0           $neighbours[ $i ] = [];
43             }
44 0           my $class = shift;
45 0           my $self = { };
46 0           bless( $self, $class );
47 0           return $self;
48             }
49              
50             sub insert_edge {
51 0     0 0   push( @{ $neighbours[ $_[ 1 ] ] }, $_[ 2 ] );
  0            
52 0           push( @{ $neighbours[ $_[ 2 ] ] }, $_[ 1 ] );
  0            
53             }
54              
55             sub neighbours {
56 0 0   0 0   if( scalar( @{ $neighbours[ $_[ 1 ] ] } ) > 0 ) {
  0            
57 0           return scalar( @{ $neighbours[ $_[ 1 ] ] } );
  0            
58             }
59 0           0;
60             }
61              
62             my @matching;
63              
64             sub maximum_matching {
65 0     0 0   for( my $i = 0; $i < $n; ++$i ) {
66 0           $matching[ $i ] = -1;
67             }
68 0           while( _sbfs() > 0 ) {
69 0           _sdfs();
70             }
71 0           my %h;
72 0           for( my $i = 0; $i < $n1; ++$i ) {
73 0 0         if( $matching[ $i ] != -1 ) {
74 0           $h{ $i } = $matching[ $i ];
75             }
76             }
77 0           %h;
78             }
79              
80             my @level;
81              
82             sub _sbfs {
83 0     0     my @queue1;
84             my @queue2;
85 0           for( my $i = 0; $i < $n1; ++$i ) {
86 0 0         if( $matching[ $i ] == -1 ) {
87 0           $level[ $i ] = 0;
88 0           push( @queue1, $i );
89             } else {
90 0           $level[ $i ] = -1;
91             }
92             }
93 0           for( my $i = $n1; $i < $n; ++$i ) {
94 0           $level[ $i ] = -1;
95             }
96 0           while( scalar( @queue1 ) > 0 ) {
97 0           $#queue2 = -1;
98 0           my $free = 0;
99 0           while( scalar( @queue1 ) > 0 ) {
100 0           my $v = pop( @queue1 );
101 0           for my $w ( @{ $neighbours[ $v ] } ) {
  0            
102 0 0 0       if( $matching[ $v ] != $w && $level[ $w ] == -1 ) {
103 0           $level[ $w ] = $level[ $v ] + 1;
104 0           push( @queue2, $w );
105 0 0         if( $matching[ $w ] == -1 ) {
106 0           $free = $w;
107             }
108             }
109             }
110             }
111 0 0         if( $free > 0 ) {
112 0           return 1;
113             }
114 0           $#queue1 = -1;
115 0           while( scalar( @queue2 ) > 0 ) {
116 0           my $v = pop( @queue2 );
117 0           for my $w ( @{ $neighbours[ $v ] } ) {
  0            
118 0 0 0       if( $matching[ $v ] == $w && $level[ $w ] == -1 ) {
119 0           $level[ $w ] = $level[ $v ] + 1;
120 0           push( @queue1, $w );
121             }
122             }
123             }
124             }
125 0           0;
126             }
127              
128             sub _sdfs {
129 0     0     for( my $i = 0; $i < $n1; ++$i ) {
130 0 0         if( $matching[ $i ] == -1 ) {
131 0           _rec_sdfs( $i );
132             }
133             }
134             }
135              
136             sub _rec_sdfs {
137 0     0     my $u = $_[ 0 ];
138 0 0         if( $u < $n1 ) {
139 0           for my $w ( @{ $neighbours[ $u ] } ) {
  0            
140 0 0 0       if( $matching[ $u ] != $w && $level[ $w ] == $level[ $u ] + 1 ) {
141 0 0         if( _rec_sdfs( $w ) == 1 ) {
142 0           $matching[ $u ] = $w;
143 0           $matching[ $w ] = $u;
144 0           $level[ $u ] = -1;
145 0           return 1;
146             }
147             }
148             }
149             } else {
150 0 0         if( $matching[ $u ] == -1 ) {
151 0           $level[ $u ] = -1;
152 0           return 1;
153             } else {
154 0           for my $w ( @{ $neighbours[ $u ] } ) {
  0            
155 0 0 0       if( $matching[ $u ] == $w && $level[ $w ] == $level[ $u ] + 1 ) {
156 0 0         if( _rec_sdfs( $w ) == 1 ) {
157 0           $level[ $u ] = -1;
158 0           return 1;
159             }
160             }
161             }
162             }
163             }
164 0           $level[ $u ] = -1;
165 0           0;
166             }
167              
168             1;
169             __END__