ABC193のD問題 Pokerを解く
ABC193で時間が足りなくて解けなかったD問題 Pokerについてのふりかえり記事です。
解説は公式がとってもわかりやすいので、自分なりに問題を解くためのポイント(気づくのに時間がかかったポイント)を挙げたいと思います。
問題をざっくりと説明すると、1〜9の数字が書かれたカードがK枚ずつあって、2名に手札が5枚ずつ配られ、そのうちの4枚がオープンになっています。この状況で高橋くんが勝つ確率を求める問題です。
大方針ですが、まずKは最大でなので、全探索はできません。
手札の種類が1〜9で、手札が1枚ずつ見えていないので、ざっくりと通り調べればいいのかなと考えつきます。
確率を求める問題なので、高橋くんが勝つケースを数えて分子にして、全ての事象の数を分母にすると求まります。
ポイント1 カードの種類の残り枚数を配列で表現する
私は最初は単純に残っているカード番号を配列に押し込めていました。
当たり前の話ですが、Kは最大でなので、配列の要素数がになったら点数を計算するのも無理です。。。
カードの種類の残り枚数を記録する配列を定義します。
例えばKが3の場合、nokori = [3] * 10として、[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]という配列を作ります。実際に使うのはnokori[1]からnokori[9]までです。
nokori = [K] * 10 for c in S: nokori[c] -= 1 for c in T: nokori[c] -= 1
2. 同じ手札が配られた場合と異なる手札の場合で場合分け
公式解説から抜粋します。
高橋くんに、青木くんにを配る方法の数は、をまだ見えていない の枚数として、
この とのケースを場合分けする発想があればミスせずにすんなりとコードを書ききれた気がします。
3. カードのパターンはintの配列ではなくて、文字列のまま扱った方が楽?
私は結局は数字として扱うから、入力の直後にintの配列に変換しました。
ところどころでint()ってやらない方がスッキリするかなと思っていたんですけど、公式解説のコードを見ると文字で扱ったままでも全然いいなと思いました。
好みの問題かもしれません。
最後に参考にならないコードかもしれませんが、書いておきます。
K = int(input()) S = input()[:4] S = [int(i) for i in S] T = input()[:4] T = [int(i) for i in T] nokori = [K] * 10 for c in S: nokori[c] -= 1 for c in T: nokori[c] -= 1 def score(cards: list) -> int: score = 0 for i in range(1, 10): s_num = cards.count(i) score += i * (10 ** s_num) return score counter = 0 for i in range(1, 10): if nokori[i] == 0: continue for j in range(1, 10): if nokori[j] == 0 or i == j: continue new_s = S[:] new_t = T[:] new_s.append(i) new_t.append(j) if score(new_s) > score(new_t): counter += nokori[i] * nokori[j] for i in range(1, 10): if nokori[i] < 2: continue new_s = S[:] new_t = T[:] new_s.append(i) new_t.append(i) if score(new_s) > score(new_t): counter += nokori[i] * (nokori[i] - 1) all_pattern = 9 * K - 8 print(counter / all_pattern / (all_pattern - 1))