C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でM面サイコロをN回投げたときの最大出目の期待値を求める方法


問題の概要

本記事では、M面のサイコロをN回投げたときに期待できる最大の出目(ドット数)を計算する方法を解説します。

このサイコロは、1番目の面に1個、2番目の面に2個、というようにドットが描かれており、M番目の面にはM個のドットが含まれます。公平なサイコロなので、各面が出る確率はすべて 1/M です。

まずは具体例を使って、何を求めるのかを確認しましょう。

入力例と出力例

入力 − M=2, N=3

出力 − 1.875

説明 − このサイコロは2つの面 {1, 2} を持ちます。

3回投げた場合、標本空間の大きさは MN = 23 = 8 通りとなります。

{(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2),
(2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)}

(1, 1, 1) の最大値 = 1
(1, 1, 2) の最大値 = 2
(1, 2, 1) の最大値 = 2
(1, 2, 2) の最大値 = 2
(2, 1, 1) の最大値 = 2
(2, 1, 2) の最大値 = 2
(2, 2, 1) の最大値 = 2
(2, 2, 2) の最大値 = 2

各ケースの確率 = 1/23 = 0.125
したがって、最大値の期待値 = (1+2+2+2+2+2+2+2) × 0.125 = 1.875

入力 − M=2, N=2

出力 − 1.75

アプローチの考え方

  • 「最大値がちょうど i になるケースの総数」は、その直前の値を利用した次の公式で求められます。
    iN − (i−1)N

    これは、「すべての出目が i 以下になる場合の数(iN)」から「すべての出目が i−1 以下になる場合の数((i−1)N)」を引くことで導かれます。

    例えば M=4、N=2 のとき、最大値が4になるケースの総数は 42 − (4−1)2 = 16 − 9 = 7 通りです。

    したがって最終的な答えは、この公式を1からMまでの各要素に適用した次の式をすべて足し合わせたものになります。

    (i × (iN − (i−1)N)) / MN

  • 関数 MaxExpect() 内では、合計を格納するために double 型の変数 max を 0 で初期化します。

  • その後、i = M から i > 0 までループを回します。

  • ループ内で上記の公式を適用し、計算結果を順次変数 max に加算していきます。

サンプルコード

#include <bits/stdc++.h>
using namespace std;
double MaxExpect(double M, double N){
    double max = 0.0, i;
    for (i = M; i; i--)
        /* 最大値を求めて合計するための公式 */
        max += (pow(i / M, N) - pow((i - 1) / M, N)) * i;
        return max;
}
int main(){
    double M = 2, N = 3;
    cout << MaxExpect(M, N);
    return 0;
}

実行結果

上記のコードを実行すると、以下の出力が得られます。

1.875

  1. C++でq回の範囲更新操作を適用した後の配列内の異なる値の個数を求める方法

    問題概要 この問題では、すべての要素が0で初期化されたサイズNの配列と、次の形式のQ個のクエリが与えられます。 update(s, e, val) → インデックスsからe(両端を含む)までのすべての要素をvalに更新するクエリです。 私たちのタスクは、指定された操作をq回適用した後の配列に含まれる異なる値の個数を求めることです。 例を使って問題を理解しましょう。 入力 : N = 6, Q = 2 Q1 = update(1, 4, 3) Q2 = update(0, 2, 4) 出力 : 3 説明 初期配列:arr[] = {0, 0, 0, 0, 0, 0} クエリ1:update(1

  2. 二分木で屈曲数が最大となるパスの長さを求めるC++プログラム

    本記事では、二分木が与えられたときに、屈曲数が最大となるパスを求める問題を解いていきます。ここで「屈曲(ベンド)」とは、パスの進行方向が左から右へ、または右から左へと切り替わる箇所のことです。具体例を見てみましょう。入力 −出力 −6この方法では、木を走査しながら直前の移動方向を記録していきます。方向が変化した時点で屈曲数を加算し、最終的にその最大値を求めます。解法のアプローチこのアプローチでは、すべてのパスを辿り、各パスにおける屈曲の総数を計算します。葉ノードに到達した時点で、これまでの屈曲数が現在の最大値を上回っていれば、答えとパスの長さを新しい値に更新します。C++による実装例#incl