# 重複組合せ生成 Repetition Combination Generator # 引数 n個 r個 値 ($n, $r, \@Value) # 戻り値 組合せ生成 (@RepetitionCombination) sub REPETITIONCOMBINATIONGENERATOR{ my ($n, $r, $Value) = @_; my @RepetitionCombination = (); my @BetweenValue = (); my @BetweenValuePos = (); my $N = int($n); my $R = int($r); my $Start = 0; my $Position = 0; my $DiffR2 = ($R - 2) - 1; my $Limit = $N; # 個数と配列数の確認 if(($N <= 0) || ($R <= 0) || ($N < $R) || ($N > @Value)){ return 0; } if($R == 1){ # 重複組合せ生成 Repetition Combination Generator @RepetitionCombination = @Value; }elsif($R == 2){ for(my $i = 0; $i < $N; $i++){ for(my $j = $i; $j < $N; $j++){ # 重複組合せ生成 Repetition Combination Generator $RepetitionCombination[$Position] = join " ", ($$Value[$i], $$Value[$j]); # 配列の位置 $Position++; } } }else { for(my $i = 0; $i < $Limit; $i++){ # 組合せで使用する値の開始位置 $Start = 0; # 両端を除く組合せで使用する配列の初期位置 for(my $j = 0; $j <= $DiffR2; $j++){ $BetweenValuePos[$j] = $i; } # 右端から一列を選ぶまで while($BetweenValuePos[0] <= $Limit){ # 組合せで使用する値 for(my $j = $Start; $j <= $DiffR2; $j++){ $BetweenValue[$j] = $$Value[$BetweenValuePos[$j]]; } # 右端まで選ぶ for(my $j = $BetweenValuePos[$DiffR2]; $j < $N; $j++){ # 重複組合せ生成 Repetition Combination Generator $RepetitionCombination[$Position] = join " ", ($$Value[$i], @BetweenValue, $$Value[$j]); # 配列の位置 $Position++; } # 組合せで使用する配列の位置を更新 for(my $j = $DiffR2; $j >= 0; $j--){ # 次に組合せで使用する値の開始位置 $Start = $j; # 配列の位置 $BetweenValuePos[$j] = $BetweenValuePos[$j] + 1; # 右端に接するまで if($BetweenValuePos[$j] < $N){ for(my $k = $j + 1; $k <= $DiffR2; $k++){ $BetweenValuePos[$k] = $BetweenValuePos[$j]; } last; } } } } } return @RepetitionCombination; }