#!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11109069 # clique use warnings; use List::Util qw( uniq sum ); my $edges = < qr/(*FAIL)/ ), map s/\s+/,/r, $edges =~ /^\w+\s+\w+/gm; my %cliques; my %seen; find( uniq sort $edges =~ /^(\w+)\s+(\w+)\b/gm ); # start with every node sub find { $seen{ my $set = "@_" }++ and return; if( my @out = $set =~ /\b(\w+)\b.+\b(\w+)\b(??{ $edges{"$1,$2"} || "" })/ ) { for my $node ( @out ) # pair of unconnected nodes, try without each one { @_ > 1 and find( grep $_ ne $node, @_ ); } } else { $cliques{ $set }++; # it is fully connected } } my $uniquecliques = ''; for ( sort { length $b <=> length $a } sort +uniq # ignore subsets keys %cliques, map tr/,/ /r, keys %edges ) { my $pattern = " $_ " =~ s/\w+/\\b$&\\b/gr =~ s/ /.*?/gr; $uniquecliques =~ /^$pattern$/m or $uniquecliques .= "$_\n"; } print "cliques:\n\n$uniquecliques"; my %scorecache; sub scoreclique { $scorecache{ $_[0] } //= do { my $score = 0; "$_[0]:\n$edges" =~ /\b(\w+)\b.*\b(\w+)\b.*:.*^\1\s+\2\s+(\d+)\b(?{ $score += $3 })(*FAIL)/ms; $score; } } my @cliques = split /\n/, $uniquecliques; my %count; $count{$_}++ for split ' ', $uniquecliques; for my $node ( map +($_) x --$count{$_}, keys %count ) # for all dups { my ($from, $to) = grep $cliques[$_] =~ /\b$node\b/, 0 .. $#cliques; my $fromscore = scoreclique($cliques[$from]) + scoreclique($cliques[$to] =~ s/\b$node\b//r); my $toscore = scoreclique($cliques[$to]) + scoreclique($cliques[$from] =~ s/\b$node\b//r); my $mod = $fromscore < $toscore ? $from : $to; # favor highest score $cliques[$mod] = join ' ', grep $_ ne $node, split ' ', $cliques[$mod]; } my $total = sum map scoreclique($_), @cliques; print "\nanswer($total):\n\n"; print "$_\n" for sort grep length, @cliques; __END__