//: [Previous](@previous) // Xcode で Editor メニュー > Show Render Markup でお読みください //import UIKit import Foundation /*: # 中学2年の数学 */ /*: ## 確率 */ /*: ## 場合の数 */ /*: ### 階乗の定義 𝑛! = 𝑛⋅(𝑛-1)⋅(𝑛-2)⋅⋯⋅1 𝑛 個のなかから 𝑛 個選んで並べる方法は 𝑛! 通りである 例えば、 4!=4⋅3⋅2⋅1=24 0!=1 … これは定義 こう定義するのは以下の理由である 階乗の定義にて 𝑛 を 𝑛+1 に置き換えてみる (𝑛+1)! = (𝑛+1)⋅𝑛⋅(𝑛-1)⋅(𝑛-2)⋅⋯⋅1 これは明らかに、 (𝑛+1)! = (𝑛+1)⋅𝑛! 𝑛=0 のとき左辺は 1! であるので、右辺が非零の 1 であるようにするには、 𝑛!=1 である必要がある */ func 階乗(n: Int) -> Int { var N = 1; for i in stride(from: n, through: 1, by: -1) { N *= i } return N } print("0!=", 階乗(n: 0)) print("1!=", 階乗(n: 1)) print("2!=", 階乗(n: 2)) print("3!=", 階乗(n: 3)) print("4!=", 階乗(n: 4)) print("5!=", 階乗(n: 5)) print("6!=", 階乗(n: 6)) /* 0!= 1 1!= 1 2!= 2 3!= 6 4!= 24 5!= 120 6!= 720 */ //: 以下は後述 func 順列の数(n: Int, k: Int) -> Int { return 階乗(n: n)/階乗(n: n-k) } func 組み合わせの数(n: Int, k: Int) -> Int { return 階乗(n: n)/(階乗(n: n-k)*階乗(n: k)) } /*: ### 順列 では、𝑛 個のなかから 𝑘 個選んで並べる方法は何通りあるだろうか まず、樹形図で理解する */ func 順列の樹形図(A: [T], n: Int, k: Int, N: inout Int, by: Int = 1) { if k == 0 { N += by print(0 < by ? "" : "×") return } for (i, a) in A.enumerated() { var A = A A.remove(at: i) // 選ばれた添字 i を除外した配列で、 print("-", a, terminator: " ") 順列の樹形図(A: A, n: n, k: k-1, N: &N, by: by) // 一つ少ない k で再起的に自身の関数を呼べばいい } } // 例題113(1) do { var N = 0 // N 通り let A = [ "a", "b", "c", "d" ] let k = 2 順列の樹形図(A: A, n: A.count, k: k, N: &N) /* - a - b - c - d - b - a - c - d - c - a - b - d - d - a - b - c */ print("\(N) 通り、\(順列の数(n: A.count, k: k)) 通り") // 12 通り } /*: ### 組み合わせ では、𝑛 個のなかから 𝑘 個選ぶ方法は何通りあるだろうか まず、樹形図で理解する */ func 組み合わせの樹形図(A: [T], n: Int, k: Int, N: inout Int, by: Int = 1) { if k == 0 { N += by print(0 < by ? "" : "×") return } for (i, a) in A.enumerated() { let count = A.count var A = A for _ in 0...i { // 添字 0 から選ばれた添字 i まですべてを除外した配列で、 A.remove(at: 0) } if !(A.count == 0 && count == n) { print("-", a, terminator: " ") } 組み合わせの樹形図(A: A, n: n, k: k-1, N: &N, by: by) // 一つ少ない k で再起的に自身の関数を呼べばいい } } // 例題113(1) do { var N = 0 // N 通り let A = [ "a", "b", "c", "d", "e" ] let k = 2 組み合わせの樹形図(A: A, n: A.count, k: k, N: &N) /* - a - b - c - d - e - b - c - d - e - c - d - e - d - e */ print("\(N) 通り、\(組み合わせの数(n: A.count, k: k)) 通り") // 10 通り } // 練習113(1)の左 do { var N = 0 // N 通り let A = [ "a", "b", "c", "d" ] let k = A.count 順列の樹形図(A: A, n: A.count, k: k, N: &N) /* - a - b - c - d - d - c - c - b - d - d - b - d - b - c - c - b - b - a - c - d - d - c - c - a - d - d - a - d - a - c - c - a - c - a - b - d - d - b - b - a - d - d - a - d - a - b - b - a - d - a - b - c - c - b - b - a - c - c - a - c - a - b - b - a */ print("\(N) 通り、\(順列の数(n: A.count, k: k)) 通り") // 24 通り } // 練習113(1)の右 do { var N = 0 // N 通り let A = [ "a", "b", "c", "d" ] let k = 2 組み合わせの樹形図(A: A, n: A.count, k: k, N: &N) /* - a - b - c - d - b - c - d - c - d */ print("\(N) 通り、\(組み合わせの数(n: A.count, k: k)) 通り") // 6 通り } // 練習113(2) do { var N = 0 // N 通り let A = [ "b", "c", "d" ], B = [ "a", "b", "c" ] 順列の樹形図(A: A, n: A.count, k: A.count, N: &N) 順列の樹形図(A: B, n: B.count, k: B.count, N: &N) /* - b - c - d - d - c - c - b - d - d - b - d - b - c - c - b - a - b - c - c - b - b - a - c - c - a - c - a - b - b - a */ print("\(N) 通り、\(順列の数(n: A.count, k: A.count) + 順列の数(n: B.count, k: B.count)) 通り") // 12 通り } // 練習113(3) do { var N = 0 // N 通り let A = [ "a", "b", "c", "d", "e", "f" ] let k = 2 組み合わせの樹形図(A: A, n: A.count, k: k, N: &N) /* - a - b - c - d - e - f - b - c - d - e - f - c - d - e - f - d - e - f - e - f */ print("\(N) 通り、\(組み合わせの数(n: A.count, k: k)) 通り") // 15 通り } /*: ### 「順列」を階乗で表す 𝑛 個のなかから 𝑘 個選んで並べる方法は何通りか 𝑛P𝑘 = 𝑛⋅(𝑛-1)⋅⋯⋅(𝑛-𝑘+1) 𝑛P𝑘 = 𝑛⋅(𝑛-1)⋅⋯⋅1/((𝑛-𝑘)⋅(𝑛-𝑘-1)⋅⋯⋅1) 𝑛P𝑘 = 𝑛!/(𝑛-𝑘)! 例えば、 ₅P₃ = 5⋅4⋅3 = 5⋅4⋅3⋅2⋅1/(2⋅1) = 60 */ print("順列") print(#"n\k\#t"#, terminator: "") for k in 0...7 { print(k, terminator: "\t") } print("") for n in 0...7 { print(n, terminator: "\t") for k in 0...n { print("\(順列の数(n: n, k: k))", terminator: "\t") } print("") } print("") /* n\k 0 1 2 3 4 5 6 7 0 1 1 1 1 2 1 2 2 3 1 3 6 6 4 1 4 12 24 24 5 1 5 20 60 120 120 6 1 6 30 120 360 720 720 7 1 7 42 210 840 2520 5040 5040 */ /*: ### 「組み合わせ」を階乗で表す 𝑛 個のなかから 𝑘 個選ぶ方法は何通りか 𝑛C𝑘 = 𝑛P𝑘/(𝑘⋅(𝑘-1)⋅⋯⋅1) 𝑛C𝑘 = 𝑛⋅(𝑛-1)⋅⋯⋅1/((𝑛-𝑘)⋅(𝑛-𝑘-1)⋅⋯⋅1⋅𝑘⋅(𝑘-1)⋅⋯⋅1) 𝑛C𝑘 = 𝑛!/((𝑛-𝑘)!𝑘!) 例えば、 ₅C₃ = 5⋅4⋅3/3⋅2⋅1 = 5⋅4⋅3⋅2⋅1/(2⋅1⋅3⋅2⋅1) = 30 */ print("組み合わせ") print(#"n\k\#t"#, terminator: "") for k in 0...7 { print(k, terminator: "\t") } print("") for n in 0...7 { print(n, terminator: "\t") for k in 0...n { print("\(組み合わせの数(n: n, k: k))", terminator: "\t") } print("") } print("") /* n\k 0 1 2 3 4 5 6 7 0 1 1 1 1 2 1 2 1 3 1 3 3 1 4 1 4 6 4 1 5 1 5 10 10 5 1 6 1 6 15 20 15 6 1 7 1 7 21 35 35 21 7 1 */ // 特にこれを「パスカルの三角形」と呼ぶ // 例題114(1) do { var N = 0 // N 通り let A = [ 0, 1, 2, 3 ], B = Array(A.dropFirst()) let k = 3 順列の樹形図(A: A, n: A.count, k: k, N: &N) 順列の樹形図(A: B, n: B.count, k: k-1, N: &N, by: -1) /* - 0 - 1 - 2 - 3 - 2 - 1 - 3 - 3 - 1 - 2 - 1 - 0 - 2 - 3 - 2 - 0 - 3 - 3 - 0 - 2 - 2 - 0 - 1 - 3 - 1 - 0 - 3 - 3 - 0 - 1 - 3 - 0 - 1 - 2 - 1 - 0 - 2 - 2 - 0 - 1 - 1 - 2 × - 3 × - 2 - 1 × - 3 × - 3 - 1 × - 2 × (注) × の分の樹形図を差し引いたもの */ print("\(N) 通り、\(順列の数(n: A.count, k: k) - 順列の数(n: B.count, k: k-1)) 通り") // 18 通り } // 例題114(2) do { var N = 0 // N 通り let A = [ 1, 2, 3 ], B = [ 0, 1, 3 ], C = Array(B.dropFirst()) let k = 2 順列の樹形図(A: A, n: A.count, k: k, N: &N) 順列の樹形図(A: B, n: B.count, k: k, N: &N) 順列の樹形図(A: C, n: C.count, k: k-1, N: &N, by: -1) /* - 1 - 2 - 3 - 2 - 1 - 3 - 3 - 1 - 2 - 0 - 1 - 3 - 1 - 0 - 3 - 3 - 0 - 1 - 1 × - 3 × (注) × の分の樹形図を差し引いたもの */ print("\(N) 通り、\(順列の数(n: A.count, k: k) + 順列の数(n: B.count, k: k) - 順列の数(n: C.count, k: k-1)) 通り") // 10 通り } /*: #### 場合の数(1) */ // 練習114(1) do { var N = 0 // N 通り let A = [ 0, 1, 2, 3, 4 ], B = Array(A.dropFirst()) let k = 2 順列の樹形図(A: A, n: A.count, k: k, N: &N) 順列の樹形図(A: B, n: B.count, k: k-1, N: &N, by: -1) /* - 0 - 1 - 2 - 3 - 2 - 1 - 3 - 3 - 1 - 2 - 1 - 0 - 2 - 3 - 2 - 0 - 3 - 3 - 0 - 2 - 2 - 0 - 1 - 3 - 1 - 0 - 3 - 3 - 0 - 1 - 3 - 0 - 1 - 2 - 1 - 0 - 2 - 2 - 0 - 1 - 1 - 2 × - 3 × - 2 - 1 × - 3 × - 3 - 1 × - 2 × (注) × の分の樹形図を差し引いたもの */ print("\(N) 通り、\(順列の数(n: A.count, k: k) - 順列の数(n: B.count, k: k-1)) 通り") // 16 通り } // 練習114(2) do { var N = 0 // N 通り let A = [ 1, 2, 3, 4 ], B = [ 0, 1, 3, 4 ], C = [ 0, 1, 2, 3 ], D = Array(B.dropFirst()), E = Array(C.dropFirst()) let k = 1 順列の樹形図(A: A, n: A.count, k: k, N: &N) 順列の樹形図(A: B, n: B.count, k: k, N: &N) 順列の樹形図(A: C, n: C.count, k: k, N: &N) 順列の樹形図(A: D, n: D.count, k: k-1, N: &N, by: -1) 順列の樹形図(A: E, n: E.count, k: k-1, N: &N, by: -1) /* - 1 - 2 - 3 - 2 - 1 - 3 - 3 - 1 - 2 - 0 - 1 - 3 - 1 - 0 - 3 - 3 - 0 - 1 - 1 × - 3 × (注) × の分の樹形図を差し引いたもの */ print("\(N) 通り、\(順列の数(n: A.count, k: k) + 順列の数(n: B.count, k: k) + 順列の数(n: C.count, k: k) - 順列の数(n: D.count, k: k-1) - 順列の数(n: E.count, k: k-1)) 通り") // 10 通り } /*: #### 場合の数(2) */ // は、省略 /*: #### 確率の意味 */ // 練習116 do { var 1が出た回数 = 0 for c in 1...1000 { if Int.random(in: 1...6) == 1 { 1が出た回数 += 1 } if log10(Double(c)).rounded() == log10(Double(c)) { print("回数: \(c),\t1が出る確率: \(Double(1が出た回数)/Double(c))") } } print("1が出る確率の理論値: \(1.0/6)") } /*: #### 確率 硬貨 */ /*: ### 「重複順列」は累乗で表す 𝑛 個のなかから 𝑘 個重複して選んで並べる方法は何通りか 𝑛^𝑘 = 𝑛⋅⋯⋅𝑛 (𝑛 が 𝑘 個の積) 例えば、 2⁸ = 2⋅2⋅2⋅2⋅2⋅2⋅2⋅2 = 256 */ func 重複順列の樹形図(A: [T], n: Int, k: Int, N: inout Int, by: Int = 1) { if k == 0 { N += by print(0 < by ? "" : "×") return } for a in A { print("-", a, terminator: " ") 重複順列の樹形図(A: A, n: n, k: k-1, N: &N, by: by) // 一つ少ない k で再起的に自身の関数を呼べばいい } } func 重複順列の数(n: Int, k: Int) -> Int { return Int(pow(Double(n), Double(k))) } // 例題118 do { var N = 0 let A = [ "表", "裏" ] let k = 3 重複順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(重複順列の数(n: A.count, k: k)) 通り") print("1枚のみ表の確率: 3/\(N)") } // 練習118 do { var N = 0 let A = [ "表", "裏" ] let k = 4 重複順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(重複順列の数(n: A.count, k: k)) 通り") print("(1) 表裏同数の確率: 6/\(N)=3/8") print("(2) 全て表裏でない確率: 1-2/\(N)=7/8") } // 例題119 do { var N = 0 let A = [ 1, 2, 3, 4, 5, 6 ] let k = 2 重複順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(重複順列の数(n: A.count, k: k)) 通り") print("(1) 出る目の和が9の確率: 4/\(N)=1/9") print("(2) 出る目の積が12の確率: 7/\(N)") } // 練習119 do { var N = 0 let A = [ 1, 2, 3, 4, 5, 6 ] let k = 2 重複順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(重複順列の数(n: A.count, k: k)) 通り") print("(1) 目の数の和が4以下の確率: 6/\(N)=1/6") print("(2) 目の数の積が15以上の確率: 13/\(N)") print("(3) 同じ目が出る確率: 6/\(N)=1/6") } // 例題120 do { var N = 0 let A = [ 1, 2, 3, 4 ] let k = 2 重複順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(重複順列の数(n: A.count, k: k)) 通り") print("(1) 3の倍数になる確率(同じ数字を使って良い): 5/\(N)") N = 0 順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(順列の数(n: A.count, k: k)) 通り") print("(2) 3の倍数になる確率(同じ数字は使えない): 4/\(N)=1/3") } // 練習120 do { var N = 0 let A = [ 1, 2, 3, 4, 5 ] let k = 2 順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(順列の数(n: A.count, k: k)) 通り") print("(1) 奇数のみの確率(カードは戻さない): 6/\(N)=3/10") N = 0 重複順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(重複順列の数(n: A.count, k: k)) 通り") print("(2) 奇数のみの確率(カードは戻す): 9/\(N)") } // 例題121 do { var N = 0 let A = [ "赤玉", "赤玉", "青玉", "青玉", "青玉" ] let k = 2 組み合わせの樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(組み合わせの数(n: A.count, k: k)) 通り") print("少なくとも1個は赤玉である確率: 7/\(N)") print("すべて青玉でない確率: 1-3/\(N)=7/\(N)") } // 練習121 do { var N = 0 let A = [ "赤玉", "赤玉", "赤玉", "青玉", "青玉", "黄玉" ] let k = 2 組み合わせの樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(組み合わせの数(n: A.count, k: k)) 通り") print("(1) 1個が青玉で1個が黄玉である確率: 2/\(N)") print("(2) 少なくとも1個は青玉である確率: 9/\(N)=3/5") print("(2') すべて青玉でない確率: 1-6/\(N)=1-2/5=3/5") } // 例題122 do { var N = 0 let A = [ "アタリ", "アタリ", "ハズレ", "ハズレ", "ハズレ", "ハズレ" ] var k = 1 順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(順列の数(n: A.count, k: k)) 通り") print("一人目が当たる確率: \(A.filter({ $0 == "アタリ" }).count)/\(N)=1/3") k = 2 N = 0 順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(順列の数(n: A.count, k: k)) 通り") print("一人目が当たり二人目も当たる場合: 2×1=\(2) 通り") print("一人目がはずれ二人目が当たる場合: 4×2=\(8) 通り") print("二人目が当たる確率: (2+8)/\(N)=10/30=1/3") } // 練習122 do { var N = 0 let A = [ "アタリ", "アタリ", "アタリ", "ハズレ", "ハズレ" ] var k = 1 順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(順列の数(n: A.count, k: k)) 通り") print("一人目が当たる確率: \(A.filter({ $0 == "アタリ" }).count)/\(N)") k = 2 N = 0 順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(順列の数(n: A.count, k: k)) 通り") print("二人目が当たる場合: \(12) 通り") print("二人目が当たる確率: 12/\(N)=3/5") } // 例題123 do { var N = 0 let A = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] let k = 2 順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(順列の数(n: A.count, k: k)) 通り") print("9で割り切れる確率: 8/\(N)=1/9") print("9で割り切れない確率: 1-8/\(N)=8/9") } // 練習123 do { var N = 0, M = 0 let A = [ 1, 2, 3, 4, 5, 6 ] let k = 3 重複順列の樹形図(A: A, n: A.count, k: k, N: &N) print("\(N) 通り、\(重複順列の数(n: A.count, k: k)) 通り") 重複順列の樹形図(A: A, n: A.count, k: k-1, N: &M) print("\(M) 通り、\(重複順列の数(n: A.count, k: k-1)) 通り") print("5で割り切れる確率: \(M)/\(N)=1/6") print("5で割り切れない確率: 1-\(M)/\(N)=5/6") } /*: #### Column あいこになる確率 1 - 3(2^𝑛 - 2)/3^𝑛 で表される */ func あいこの確率(n: Int) -> Double { return 1.0 - Double(3*重複順列の数(n: 2, k: n) - 2)/Double(重複順列の数(n: 3, k: n)) } /*: #### 全射の数 ∑_{i=1}^k​(−1)^{k−i}kPi⋅i^n で表される すると「あいこになる確率」は全射の数を使って以下のようにも表される (3 + ∑_{i=1}^k​(−1)^{k−i}kPi⋅i^n)/(3^n) 分子の第1項の3は「グー・チョキ・パー」のいずれかを揃って全員が出す場合の数を意味していて、第2項は「グー・チョキ・パー」のグループ分けを行なった場合(全射)の数を表していて、分母はすべての場合の数を表している */ func 全射の数(n: Int, k: Int) -> Int { var s = 0 for i in 0..(A: [T], n: Int, k: Int, N: inout Int, by: Int = 1) { // 思案中 } #endif func 重複組み合わせの数(n: Int, k: Int) -> Int { return 組み合わせの数(n: n + k - 1, k: n) } print("重複組み合わせ") print(#"n\k\#t"#, terminator: "") for k in 0...7 { print(k, terminator: "\t") } print("") for n in 0...7 { print(n, terminator: "\t") for k in 0...n { print("\(重複組み合わせの数(n: n, k: k))", terminator: "\t") } print("") } print("") /* n\k 0 1 2 3 4 5 6 7 0 1 1 1 1 2 1 2 3 3 1 3 6 10 4 1 4 10 20 35 5 1 5 15 35 70 126 6 1 6 21 56 126 252 462 7 1 7 28 84 210 462 924 1716 */ // n 個を k 人で分ける場合の数、但し、配分がない人がいても良い do { //var N = 0 let A = [ "ドラム", "ピアノ", "ベース", "ギター" ] let k = 3 //重複組み合わせの樹形図(A: A, n: A.count, k: k, N: &N) // 思案中 //print("\(N) 通り、\(重複組み合わせの数(n: A.count, k: k)) 通り") // 思案中 print("\(重複組み合わせの数(n: A.count, k: k)) 通り") } //: [Next](@next)