横丁の名探偵

トップ > 横丁の日記 > ペアマッチ(新婚さんいらっしゃい!)期待値計算

/******************************************************************************
ペアマッチ(新婚さんいらっしゃい!)で獲得できる商品数の期待値を求める。
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#define N0 0 /* 基準値 */
#define N1 1 /* 単位の数 */
#define N2 2 /* ペアの数 */
#define N4 4 /* 状態の数 */
#define N8 8 /* 賞品の数 */
#define N9 9 /* N8 + N1 */
#define SENKO 0 /* 先攻 */
#define KOKO 1  /* 後攻 */
double dShohin[9][9]; /* 先攻、後攻がそれぞれ獲得した賞品数ごとの確率 */
static int nZobun[4][N2] = {N1,N0 , N0,N1 , N1,N0 , N0,N1};
                                                   /* 状態ごとの獲得賞品増分 */
/******************************************************************************
機能:パネルをオープンして、次に進める。
引数:
 1 (I) nMikai  2枚とも場所が不明な賞品の数
 2 (I) nKataho 1枚の場所が判明している賞品の数
 3 (I) nHanmei 2枚とも場所が判明しているが、まだ獲得されていない賞品の数
 4 (I) nSenko  先攻ペアが獲得した賞品の数
 5 (I) nKoko   後攻ペアが獲得した賞品の数
 6 (I) prob    その状態に至る確率
 7 (I) status  状態(0.先攻新郎、1.後攻新郎、2.先攻新婦、3.後攻新婦)
戻り値:なし
******************************************************************************/
void junban(int nMikai , int nKataho , int nHanmei , int nSenko , int nKoko ,
          double prob , int status)
{
    double t1 , t2; /* 次の状態の確率計算用一時変数 */
    double nextProb; /* 次の状態の確率 */
    if(status == N4 || nSenko + nKoko == N8) {
        dShohin[nSenko][nKoko] += prob;
        return;
    }
    t1 = 2.0 * (double)nMikai + (double)nKataho;
    t2 = t1 * (t1 - 1.0);
    if(nHanmei == N0) {
	if(t1 != 0.0) {
/* 1枚目で、片方が判明している賞品をオープンして獲得 */
            nextProb = prob * (double)nKataho / t1;
            junban(nMikai , nKataho - 1 , N0 , nSenko + nZobun[status][SENKO] ,
                 nKoko + nZobun[status][KOKO] , nextProb , status);
        }
        if(t2 != 0.0) {
/* 1枚目、2枚目で同じ賞品をオープンして獲得 */
            nextProb = prob * 2.0 * (double)nMikai / t2;
            junban(nMikai - 1 , nKataho , N0 , nSenko + nZobun[status][SENKO] ,
                 nKoko + nZobun[status][KOKO] , nextProb , status);
/* 1枚目、2枚目とも初めての賞品 */
            nextProb = prob * 2.0 * (double)nMikai *
                       (2.0 * (double)nMikai - 2.0) / t2;
            junban(nMikai - 2 , nKataho + 2 , N0 , nSenko, nKoko ,
                 nextProb , status + N1);
/* 1枚目が初めての賞品、2枚目が片方が判明している賞品 */
            nextProb = prob * 2.0 * (double)nMikai * (double)nKataho / t2;
            junban(nMikai - 1 , nKataho , N1 , nSenko , nKoko , nextProb ,
                 status + N1);
        }
    }
    else {
/* 2枚とも判明している賞品を獲得 */
        junban(nMikai , nKataho , N0 , nSenko + nZobun[status][SENKO] ,
             nKoko + nZobun[status][KOKO] , prob , status);       
    }
}
/******************************************************************************
機能:メイン
引数:なし
戻り値:EXIT_SUCCESS
******************************************************************************/
int main(void)
{
    int i , j; /* ループ制御変数 */
    double sProb[N9][N2]; /* 獲得数ごとの確率 */
    static double dKitai[N2] = {(double)N0 , (double)N0}; /* 期待値 */
    for(i = N0 ; i < N9 ; i++) {
        sProb[i][SENKO] = sProb[i][KOKO] = (double)N0;
        for(j = N0 ; j < N9 ; j++) dShohin[i][j] = (double)N0;
    }
    junban(8 , N0 , N0 , N0 , N0 , 1.0 , N0);
    for(i = N0 ; i < N9 ; i++) {
        for(j = N0 ; j < N9 ; j++) {
            sProb[i][SENKO] += dShohin[i][j];
            sProb[j][KOKO]  += dShohin[i][j];
			dKitai[SENKO] += ((double)i * dShohin[i][j]);
            dKitai[KOKO]  += ((double)j * dShohin[i][j]);
        }
    }
    for(i = N0 ; i < N9 ; i++) {
        printf("%d %8.5lf %8.5lf\n" , i , sProb[i][SENKO] , sProb[i][KOKO]);
    }
    printf("期待値 先攻:%6.3lf 後攻:%6.3lf\n" , dKitai[SENKO] , dKitai[KOKO]);
    return(EXIT_SUCCESS);
}