LoginSignup
9
6

More than 1 year has passed since last update.

今さらながら、Rubyで順列・組み合わせを実装してみた

Last updated at Posted at 2020-04-28

プログラミング問題に登場する「最短経路問題」とかさっぱりわからなかったので、いろいろ調べてみた。
どうやら、中学受験とか高校数学とかで出てくる、順列・組み合わせを勉強しとくと良いらしい。
そこで、Rubyの組み込みメソッドを使わずに、パターンを列挙するコードを再帰呼び出しで実装した。

階乗

factorial
5! = 5 * 4 * 3 * 2 * 1
n! = n * (n - 1) * (n - 2) ・・・* 3 * 2 * 1
n! = n * (n - 1)!    と再帰で定義できる
「0! = 1」と定義しておく

# 階乗を計算:ループ

def factorial(number, result = 1)
    return result if number <= 1
    factorial(number - 1, result * number)
end

puts factorial(10)

paiza.IO
https://paiza.io/projects/6Ic-z9ulnG7Ygxk4wUuR8Q

順列

permutation
n個の物を並べるパターン
とりあえず、物は、ひとつずつ別のもの。
順番が違えば、違うパターンと考える
パターン数は、n!になる

n個の物からr個を選んで並べるパターン
n[** P]r = n! / (n - r)!


1, 2, 3 の順列を列挙すると、123, 132, 213, 231, 312, 321 の6パターン

# 順列の列挙:再帰
def permutation(array, number, temp = "", result = [])
    return result << temp if temp.size >= number

    array.each_with_index do |value, i|
        copy_array = array.clone
        copy_array.delete_at(i)
        permutation(copy_array, number, temp + value, result)
    end
    return result
end

result = permutation(["A", "B", "C", "D"], 3)
puts result.size
p result

paiza.IO
https://paiza.io/projects/OthkafOwgKZwcF9OCrkOqA

Ruby 組み込みメソッド
Array#permutation (Ruby 2.7.0 リファレンスマニュアル)
https://docs.ruby-lang.org/ja/latest/method/Array/i/permutation.html

0の階乗を1と定義する理由 | 高校数学の美しい物語
https://mathtrain.jp/0nokaijo

同じものを含む順列

「同じものを含む順列」と、これでひとつの手法になっている。
最短経路問題に、これを使う。
たとえば、a,a,b,b,b,c,d の7つの文字を一列に並べて順列を作る
この場合、並べる物に同一の物が含まれていて区別できない
既に選ばれたものを並べ替える、とも言える

𝑛 個の中に同じものが 𝑝 個、𝑞 個、𝑟 個・・・ずつあるとき、その並べ方の総数は
n! / p! * q! * r!


"A", "B", "B", "C"から2つ選んで並べる
"AB", "AC", "BA", "BB", "BC", "CA", "CB"

# 同じ物を含む順列:再帰
def mults_permutation(array, number, temp = "", result = [])
    if temp.size >= number
        
        if !result.include?(temp) then
            result << temp
        end
        
        return
    end

    array.each_with_index do |value, i|
        
        copy_array = array.clone
        copy_array.delete_at(i)
        mults_permutation(copy_array, number, temp + value, result)
        
    end
    
    return result
end


# result = mults_permutation(["O", "O", "O", "I", "I"], 5)
result = mults_permutation(["A", "B", "B", "C"], 2)
puts result.size
p result

paiza.IO
https://paiza.io/projects/RwoyHv2T36svGflpP7nupg

同じものを含む順列の公式 意味と使い方 | | 高校数学の知識庫
http://math-souko.jp/%E5%90%8C%E3%81%98%E3%82%82%E3%81%AE%E3%82%92%E5%90%AB%E3%82%80%E9%A0%86%E5%88%97%E3%81%AE%E5%85%AC%E5%BC%8F%E3%80%80%E6%84%8F%E5%91%B3%E3%81%A8%E4%BD%BF%E3%81%84%E6%96%B9/

重複順列

sequence with repetition
重複を許して、n個の物からr個を選んで並べるパターン
通常の順列は、ひとつずつ別の物と考える
重複順列は、同じ物が複数回、選ばれてもいい。ゼロ回でもいい。
1から4までの番号が付いた異なる箱が4つあるとき、赤、白のボールを1個ずつ入れるパターンは何通りあるか。

重複順列のパターン数 = n ^ r


ABCから、2文字選ぶ重複順列
"AA", "AB", "AC", "BA", "BB", "BC", "CA", "CB", "CC"

# 重複順列の列挙:再帰
def sequence(array, number, temp = "", result = [])
    return result << temp if temp.size >= number

    array.each do |value|
        sequence(array, number, temp + value, result)
    end
    return result
end

result = sequence(["A", "B", "C"], 2)
puts result.size
p result

paiza.IO
https://paiza.io/projects/awyYFUAwo_BxdDLjO0RCEg

Ruby 組み込みメソッド
Array#repeated_permutation (Ruby 2.7.0 リファレンスマニュアル)
https://docs.ruby-lang.org/ja/latest/method/Array/i/repeated_permutation.html

重複順列=同じものを並べられる順列。その考え方をイラストで解説 - 理数白書
https://www.risuuhakusyo.com/cyouhuku-junretu

組み合わせ

Combination
異なる n 個から r 個取り出したときのパターン
順番は考慮しない。順番が違っても、同じパターンと考える

n[** C]r = n! / (n - r)! * 1/r!
r! :同じ要素で順番が異なるパターンで割る


A, B, C, Dから2個取り出す組み合わせ > AB, AC, AD, BC, BD, CD

# 組み合わせの列挙: 再帰
def combination(array, number, temp = "", result = [])
    return result << temp if temp.size >= number
    
    array.each_with_index do |top, i|
        sub_array = array[i + 1, array.size]
        # p "#{temp + top}, #{sub_array}"
        combination(sub_array, number, temp + top, result)
    end
    return result
end

result = combination(["A", "B", "C", "D", "E"], 2)
p result.size
p result

paiza.IO
https://paiza.io/projects/lmey5fFLbARUhlIsL9MUMQ

Ruby 組み込みメソッド
Array#combination (Ruby 2.7.0 リファレンスマニュアル)
https://docs.ruby-lang.org/ja/latest/method/Array/i/combination.html

順列と組み合わせの公式とその違い【問題付き】 | 理系ラボ
https://rikeilabo.com/formula-and-diferrence-of-Permutation-combination

重複組み合わせ

repeated_combination
異なる n 種類のものから[[重複]]を許して r 個取る組合せ
総数は、n+r-1[** C]r


たとえば、赤・白・黒の3種類の玉から、重複を許して3個をとる組み合わせは

赤赤赤、赤赤白、赤白白、赤白黒、赤赤黒、赤黒黒、白白黒、白黒黒、白白白、黒黒黒

玉3個と境2個について、 〇|〇|〇 を使った、[同じものを含む順列]と考えられる。
〇が玉の位置、|が境界の位置。境界が色の境目になる。境界数は、「玉の種類数 - 1」
すると、左から、玉の位置が赤・白・黒に相当

OOOII > 赤赤赤
OOIOI > 赤赤白
OOIIO > 赤赤黒
OIOOI > 赤白白
OIOIO > 赤白黒
OIIOO > 赤黒黒
IOOOI > 白白白
IOOIO > 白白黒
IOIOO > 白黒黒
IIOOO > 黒黒黒

また、5個の場所(_ _ _ _ _)から、3個を選んだ[組み合わせ]と考えることもできる

# 重複組み合わせの列挙。同じ物を含む順列を利用した

def mults_permutation(array, number, temp = "", result = [])
    if temp.size >= number
        
        if !result.include?(temp) then
            result << temp
        end
        
        return
    end

    array.each_with_index do |value, i|
        
        copy_array = array.clone
        copy_array.delete_at(i)
        mults_permutation(copy_array, number, temp + value, result)
        
    end
    
    return result
end

def repeated_combination(array, number)
    pos = Array.new(number, "o") +  Array.new(array.size - 1, "I")
    pattern = mults_permutation(pos, pos.size)
    # p pattern
    
    result = []
    pattern.each do |value|
        value_array = value.split("I")
        item_list = ""
        value_array.each_with_index do |item, i|
            item_list += item.gsub(/(o)/, array[i])
        end
        result << item_list
    end
    
    return result    
end

result = repeated_combination(["A", "B", "C"], 4)
p result.size
p result

paiza.IO
https://paiza.io/projects/xfWb-Hulyiphdgisd2vN6g

Ruby 組み込みメソッド
Array#repeated_combination (Ruby 2.7.0 リファレンスマニュアル)
https://docs.ruby-lang.org/ja/latest/method/Array/i/repeated_combination.html

重複組合せとは – 重複組合せの公式の意味 | きぬごしのお受験ブログ
https://toufumentals-kinugoshi.com/duplicate-combination/

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6