-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTarjan
executable file
·89 lines (77 loc) · 2.12 KB
/
Tarjan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/local/bin/perl
#u# http://rosettacode.org/wiki/Tarjan
#c# 2018-11-19 >RC, 2020-03-09 <RC
#p# OK
#n# use of the lexical subroutine required else the variables will not be shared
my @res;
use v5.36.0;
use List::Util qw(min);
sub tarjan (%k) {
my (%onstack, %index, %lowlink, @stack, @connected);
my sub strong_connect ($vertex, $i) {
$index{$vertex} = $i;
$lowlink{$vertex} = $i + 1;
$onstack{$vertex} = 1;
push @stack, $vertex;
for my $connection (@{$k{$vertex}}) {
if (not defined $index{$connection}) {
__SUB__->($connection, $i + 1);
$lowlink{$vertex} = min($lowlink{$connection}, $lowlink{$vertex});
}
elsif ($onstack{$connection}) {
$lowlink{$vertex} = min($index{$connection}, $lowlink{$vertex});
}
}
if ($lowlink{$vertex} eq $index{$vertex}) {
my @node;
do {
push @node, pop @stack;
$onstack{$node[-1]} = 0;
} while $node[-1] ne $vertex;
push @connected, [@node];
}
}
for (sort keys %k) {
strong_connect($_, 0) unless $index{$_};
}
@connected;
}
my %test1 = (
0 => [1],
1 => [2],
2 => [0],
3 => [1, 2, 4],
4 => [3, 5],
5 => [2, 6],
6 => [5],
7 => [4, 6, 7]
);
my %test2 = (
'Andy' => ['Bart'],
'Bart' => ['Carl'],
'Carl' => ['Andy'],
'Dave' => [qw<Bart Carl Earl>],
'Earl' => [qw<Dave Fred>],
'Fred' => [qw<Carl Gary>],
'Gary' => ['Fred'],
'Hank' => [qw<Earl Gary Hank>]
);
print "Strongly connected components:\n";
push @res, join ', ', sort @$_ for tarjan(%test1);
print "\nStrongly connected components:\n";
push @res, join ', ', sort @$_ for tarjan(%test2);
say my $result = join "\n", @res;
my $ref = <<'EOD';
0, 1, 2
5, 6
3, 4
7
Andy, Bart, Carl
Fred, Gary
Dave, Earl
Hank
EOD
use Test::More;
chop $ref;
is($result, $ref);
done_testing;