他カテゴリ

順列と組み合わせ

nonstop-iida's icon'
  • nonstop-iida
  • 2020/03/05 10:02

さあ、お待ちかねの基本情報技術者試験のお勉強の時間です。(というより、自分の知識定着のためのアウトプット)

Content image

 

1.場合の数

順列や組み合わせに入る前に、まずは場合の数について書きます。~した場合に、何通りのパターンがあるか?これが場合の数です。

(1) 積の法則

2つの事象A・Bがある場合に、Aがx通り、Bがy通りである場合、場合の数は「x×y通り」となります。

例えば、トランプ(ジョーカー抜き)から2枚引いた場合の組み合わせは何通りか?

とすると、1枚目を引く時は52枚が選ばれる可能性があります。しかし、2枚目を引く時は1枚目を覗いた51枚が選ばれる可能性があります。トランプはマーク毎に13個の数字があり、かぶることはないため、52×51通り(2,652通り)が場合の数となります。

(2) 和の法則

次に事象Cとして、トランプから1枚も引かないという選択肢が有り得たとします。事象C単体の場合の数は1通りですが、事象A・B・C全体で見た時には、2,652通り+1通り=2,653通りです。

これは、事象A(1枚引く)・事象B(もう一枚引く)に対して、事象C(一枚も引かない)事は同時に起こり得ないからです。

なので2枚引く場合は、2,652通りあるが引かない1通りもあるので、場合の数としては2,653通りとなるわけです。

Content image

2.順列

(1) 順列の考え方 

順列は、先ほどのトランプのように全体から何個かを順番に場合の数を求めるものです。順番に選んでいくので、1枚目・2枚目と選べる母数が減っていきます。このように選定場面が区別されるものは順列としてとらえます。(重複を排除しなくていい)

反対に2枚選ぶだけの場合、例えば♦のAと♠のAを選ぶのと、♠のAと♦のAを選ぶのは、結果として同一であるため組み合わせとしてとらえます。(重複を排除する必要あり)

例えば1枚目に♡のA・2枚目に♧のJを選んだ場合と、1枚目に♧のJ・2枚目に♡のAを選んだ場合、組み合わせでは重複としてカウントしませんが、順列ではカウントします。

1度選んだものは再度選べないことから、以下の通りとなります。

Content image

(2) 公式

公式ではnPr =  n × (n-1)×(n-2)・・・×(n-r+1)となります。

(トランプの例の場合、52×(52-1)×(52‐3+1)ですね)

(3) Pythonで順列を求める

Pythonで順列を求める計算をしてみましょう。順列を求める場合は、イテレータ生成ツールitertoolsを使います。

import itertools

card = []
mark = {1:'♥',2:'♦',3:'♧',4:'♠'}
numbers = [n for n in range(1,14)]

for i, m in mark.items():
   for num in numbers:
       card.append(str(m) + str(num))

permutations_  = set(itertools.permutations(card, 3))

print(len(permutations_)) #132600

for p in permutations_:
   print(p)

<大まかな解説>

➀ cardという空のリストを作成し、トランプのマークを格納したmarkという辞書と、1~13までの数字を格納したnumbersリストを用意して、2重ループで52枚のトランプカードを作成。

➁ 集合を作るsetを使い、itertools.permutations()の引数にcardリストと3枚選ぶので3を設定する。ちなみに、permutationsは英語で順列のことです。

print(len(permutations))で要素数を出力すると、132,600となります。(52×51×50)

更にforループで組み合わせを出力していますが、132,600通りなので、大変なことになります。飽きたら、ctrl + cでプログラムを止めてください(笑)

こんな感じになります(笑)

itertoolsについてのドキュメント

Content image

3.組み合わせ

次に組み合わせです。

(1) 考え方

先ほど、順列の説明で書いたように、全体から特に順番等を決めずに選ぶだけの場合、組み合わせが重複する可能性があり、これは排除する必要があります。

例えば、先ほどのトランプの例でいうと、順番を考えずに3枚選んだ場合の組み合わせは何通りでしょうか?という問題になりますね。

この場合、以下図の通りカードの並びを考慮しないので、発声する重複分を排除する必要があるんですね。

Content image

上の図のとおり、3枚の組み合わせには6パターンが存在するわけです。つまり、選べる全てのパターン(これは順列ですね)を、この重複パターンで割ると、重複を排除した組合せが出てくるわけです。

トランプだと数が大きすぎてイメージがわかないと思うので、1~5までの数字カードから3枚選んだ場合を考えてみましょう。

総数(順列)は5×4×3で60通りですね。これを6パターンで割ると・・・

10通りとなります。

1始まりのパターンが・・・

{1・2・3} {1・2・4} {1・2・5} {1・3・4} {1・3・5} {1・4・5} 6パターン

2始まりのパターンが・・・

{2・3・4} {2・3・5} {2・4・5} 3パターン

3始まりのパターンが・・・

{3・4・5} 1パターン

これ以外のパターンは全て並び順が違うだけの重複なので10通りですね。

(2) 公式

組み合わせの公式はnCr = nPr/r! = n!/r!(n-r)! です。

!がついているのは階乗(5×4×3×2×1と階段状に乗算するもの)です。

nPr/r!はまさに60/3×2×1と、上でやった解き方です。

n!/r!(n-r)!が個人的には理解し辛かったのですが、nのr個目以下の階乗をさせる分、

分母に(n-r)!を加えたと考えたら理解できました。

(間違ってたらご指摘くださいm(_ _)m)

(3) Pythonで組み合わせを求める

順列で利用したitertoolsで組み合わせも対応可能です。

なんと、permutationsのところを、combinationsに書き換えるだけでOKです。(combinationsは組合せという意味です)

import itertools
card = []
mark = {1:'♥',2:'♦',3:'♧',4:'♠'}
numbers = [n for n in range(1,14)]

for i, m in mark.items():
   for num in numbers:
       card.append(str(m) + str(num))

permutations_  = set(itertools.combinations(card, 3))

print(len(permutations_))

for p in permutations_:
   print(p)

実行してみると・・・

Content image

22,100通りとなりました。

公式にあてはめると・・・52C3 = 52×51×50・・・・1×1 ÷ 3×2×1(49×48…×1)となります。

重複するところを端折ると、132,000÷6で22,100ですね。

4.最後に

おまけです。順列の場合に、仮に同じカードを複数回選んでよいという条件が加わったらどうでしょうか?

これを重複順列と言いますが、実はこれもitertoolsで対応可能です。productという処理が可能です。

import itertools
card = []
mark = {1:'♥',2:'♦',3:'♧',4:'♠'}
numbers = [n for n in range(1,14)]

for i, m in mark.items():
   for num in numbers:
       card.append(str(m) + str(num))

permutations_  = set(itertools.product(card, card, card))

print(len(permutations_))

for p in permutations_:
   print(p)               

実行すると、以下のとおり140,608通りとなりました。

一番上の組み合わせを見ると、まさに♧13が重複してますね!

Content image

最後まで、読んでいただき誠にありがとうございました!

 

 

 

 

 

Supporter profile iconSupporter profile icon
Article tip 2人がサポートしています
獲得ALIS: Article like 25.14 ALIS Article tip 5.00 ALIS
nonstop-iida's icon'
  • nonstop-iida
  • @nonstop-iida
ノンストップ飯田と申します。会社員ですが、趣味でやってるPythonと歌うのが好きです。曲も書きます。twitter:@nonstop_iida

投稿者の人気記事
コメントする
コメントする
こちらもおすすめ!
Eye catch
クリプト

約2年間ブロックチェ-ンゲームをして

Like token Tip token
61.20 ALIS
Eye catch
クリプト

Bitcoin史 〜0.00076ドルから6万ドルへの歩み〜

Like token Tip token
947.13 ALIS
Eye catch
クリプト

ジョークコインとして出発したDogecoin(ドージコイン)の誕生から現在まで。注目される非証券性🐶

Like token Tip token
38.31 ALIS
Eye catch
クリプト

NFT解体新書・デジタルデータをNFTで販売するときのすべて【実証実験・共有レポート】

Like token Tip token
121.79 ALIS
Eye catch
クリプト

17万円のPCでTwitterやってるのはもったいないのでETHマイニングを始めた話

Like token Tip token
46.60 ALIS
Eye catch
他カテゴリ

機械学習を体験してみよう!(難易度低)

Like token Tip token
124.82 ALIS
Eye catch
他カテゴリ

オランダ人が語る大麻大国のオランダ

Like token Tip token
46.20 ALIS
Eye catch
他カテゴリ

SASUKEオーディションに出た時の話

Like token Tip token
35.87 ALIS
Eye catch
他カテゴリ

京都のきーひん、神戸のこーへん

Like token Tip token
12.10 ALIS
Eye catch
トラベル

わら人形を釘で打ち呪う 丑の刻参りは今も存在するのか? 京都最恐の貴船神社奥宮を調べた

Like token Tip token
486.35 ALIS
Eye catch
トラベル

梅雨の京都八瀬・瑠璃光院はしっとり濃い新緑の世界

Like token Tip token
216.64 ALIS
Eye catch
クリプト

Bitcoinの価値の源泉は、PoWによる電気代ではなくて"競争原理"だった。

Like token Tip token
159.32 ALIS