【Python】区別がつかない同じものを含む順列の計算

■概要

「1、2、2、3、3」や「A、A、B、C、D、D」など、区別がつかない同じものを含む順列について、机上計算およびPythonを使用した計算処理の2種類の解答方法を示す。

■同じものを含む順列

5つの数字「1、2、2、3、3」を順番に並び替えた場合の数を考える。

下図は、見分けやすいように色分けしているが、同じ「1、2、2、3、3」であり、これらの重複分を合わせて1通りとする。

▼同じものを含む順列の公式

n個の値を全て使用するとき、同じものがそれぞれ「p個、q個、r個、・・・」あるとき、場合の数は、以下の公式で求めることができる。

「1、2、2、3、3」の個数は、それぞれ、「1:1個」、「2:2個」、「3:2個」であるため、順番に並び替えた場合の数は、以下の通りである。

なお、個数が1個の場合は、「1!」を計算しても「1」であるため、省略することができる。

■例題

▼問1

6つの数字「1、3、3、5、7、7」を全て使用して6桁の数字を作る時の場合の数を求める。

▼問2

8つの文字「anotools」を全て使用して文字列を作成する時の場合の数を求める。

■机上計算

▼問1

6つの数字「1、3、3、5、7、7」の個数は、それぞれ、「1:1個」、「3:2個」、「5:1個」、「7:2個」であるため、順番に並び替えた場合の数は、以下の通りである。

▼問2

8つの文字「anotools」の個数は、それぞれ、「a:1個」、「n:1個」、「o:3個」、「t:1個」、「l:1個」、「s:1個」であるため、順番に並び替えた場合の数は、以下の通りである。

■Pythonによる実装

▼フローチャート

同じものを含む順列を計算する関数について、フローチャートを下図に示す。

▼プログラム仕様

<処理名:同じものを含む順列を計算する関数>

・引数と戻り値

項目内容
第1引数リスト型対象のデータ全量
戻り値int型同じものを含む順列の計算結果

・処理概要

入力処理内容出力
第1引数のリスト型データをタプル型に変換する。
★タプル型に変換することで、重複分が削除される。
(イメージ)
リスト型:[1, 2, 2, 3, 3]
タプル型:(1, 2, 3)
同じ個数の計算結果初期値をセットする。
初期値:1
※「p!×q!×r!・・・」の計算結果格納変数
■ループ処理:タプル型の要素数分繰り返し
|▼条件分岐:リスト型のデータ
|【同じものがある場合(>1)】
||同じ個数の計算結果に階乗結果を追加する。(p! * q! * r!…)
|▲
リスト型の全量をセットする。
場合の数を算出する。
n! / (p! * q! * r!…)

▼サンプルコード

import math


# 同じを含む順列を計算する関数
def same_permutation(list_data:list) -> int:
    # タプル型に変換し、同じものを削除
    taple_data = set(list_data)

    # 同じ個数の計算結果初期値
    same_count_result = 1

    # タプル型の要素数分繰り返し
    for i in taple_data:
        # 同じものがある場合
        if list_data.count(i) > 1:
            # 同じ個数の計算結果に階乗結果を追加(p! * q! * r!...)
            same_count_result = same_count_result * math.factorial(list_data.count(i))

    # リストの全量をセット
    count_all_data = len(list_data)

    # 場合の数を算出(n! / (p! * q! * r!...))
    ans = math.factorial(count_all_data) / same_count_result

    return int(ans)


if __name__ == '__main__':
    q1 = [1,3,3,5,7,7]
    print('問1:', same_permutation(q1), '通り')

    q2 = ['a', 'n', 'o', 't', 'o', 'o', 'l', 's']
    print('問2:', same_permutation(q2), '通り')

▼実行結果

問1: 180 通り
問2: 6720 通り

コメント