重複を持たない組合せを深さ優先と幅優先の両方で羅列する(Perl)
2012-03-08-3
[Algorithm][Programming]
とあるタスクにおいて、重複を持たない組合せ(コンビネーション)を羅列する必要があったので、復習も兼ねてPerlでゼロから書いてみた。
(参考:Wikipedia:組合せ_(数学))
異なる n 個のものから異なる m 個を選ぶ。高校の数学でやった「場合の数」。
数はどうでもいいので、実際の組み合わせを深さ優先と幅優先の両方の方式で羅列する。汎用性のため、リスト(配列)そのものから選ぶのではなく、インデックス(配列の添字)から選ぶ。
■コード(combination.pl):
■実行例:
(参考:Wikipedia:組合せ_(数学))
異なる n 個のものから異なる m 個を選ぶ。高校の数学でやった「場合の数」。
数はどうでもいいので、実際の組み合わせを深さ優先と幅優先の両方の方式で羅列する。汎用性のため、リスト(配列)そのものから選ぶのではなく、インデックス(配列の添字)から選ぶ。
■コード(combination.pl):
#!/usr/bin/perl use strict; use warnings; my @chars = qw(A B C D E F G H I J K); my $n = 5; # 全体の数 my $m = 3; # 選ぶ数 my @results = (); df_combination($n, $m, []); print join("", map {join(",", @$_)."\n"} @results); print join("", map {join("", map {$chars[$_]} @$_)."\n"} @results); @results = (); bf_combination($n, $m, []); print join("", map {join(",", @$_)."\n"} @results); print join("", map {join("", map {$chars[$_]} @$_)."\n"} @results); # 深さ優先探索 Depth first search sub df_combination { my ($n, $m, $p_ref) = @_; if (@$p_ref == $m) { push @results, $p_ref; return; } my $lv = (not @$p_ref) ? 0 : $p_ref->[-1] + 1; for (my $i = $lv; $i < $n; $i++) { df_combination($n, $m, [@$p_ref, $i]); } } # 幅優先探索 Breadth first search sub bf_combination { my ($n, $m) = @_; my @nodes = map {[$_]} (0..$n-1); while (@nodes) { my $v = shift @nodes; my @vs = @$v; if (@vs == $m) { push @results, $v; next; } my $lv = $vs[$#vs]; foreach my $i ($lv+1..$n-1) { push @nodes, [@vs, $i]; } } }
■実行例:
./combination.pl 0,1,2 0,1,3 0,1,4 0,2,3 0,2,4 0,3,4 1,2,3 1,2,4 1,3,4 2,3,4 ABC ABD ABE ACD ACE ADE BCD BCE BDE CDE 0,1,2 0,1,3 0,1,4 0,2,3 0,2,4 0,3,4 1,2,3 1,2,4 1,3,4 2,3,4 ABC ABD ABE ACD ACE ADE BCD BCE BDE CDE
この記事に言及しているこのブログ内の記事