※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

問い389

1つの偏りのない四面体のサイコロを振り、出た目Tを記録する。
T個の偏りのない六面体のサイコロを振り、出た目の合計Cを記録する。
C個の偏りのない八面体のサイコロを振り、出た目の合計Oを記録する。
O個の偏りのない十二面体のサイコロを振り、出た目の合計Dを記録する。
D個の偏りのない二十面体のサイコロを振り、出た目の合計Iを記録する。
Iの分散を四捨五入して小数点以下第4位まで求めよ。

解法
この問題は難しい、最初読んだとき一瞬何を問われてるか意味がわからなかった。
とりあえず多段動的計画法とでも呼べそうなものをでっちあげて解こうとしてるもののコードが間違ってないかlong doubleで精度や桁数が足りるのか,最後の四捨五入でほんの少しだけ違う値にならないか?
4面の結果から動的計画法で6面の組み合わせ数を求め、6面の結果から8面、、12面から20面の結果を求めるコードです。
最後に20面さいころを振った場合、目の合計がnになる場合の組み合わせ数をmemo20[n]に保管してみました。
一応数学の定義通りに平均と分散を出してみたのですが不正解となっています。

コードに記述ミスがあるのか精度が悪いのか方法が悪いのかよくわからない状態です。



#include<stdio.h>
#include<iostream>
#include<string.h>
#include <iomanip>
#include <quadmath.h>
__float128 memo6[25]={0},memo8[193]={0},memo12[2305]={0},memo20[46081]={0};//memo[目の合計]の組み合わせ数が入る
__float128 memo4[5]={0,1,1,1,1};//4面ダイスからスタート
//一般化しないとこの問題は難しすぎるので抽象化して解く
__float128 memo[46081]={0},memo2[46081];//memo[さいの目の合計数]
//__float128 memo[25],memo2[25];
void calc(int d,int max,__float128* multiMemo,__float128* nextMemo){
	//dはダイスの面数、maxはダイスの個数,multiMemoはさいころを転がす回数の組、nextMemoは次の結果
	//動的計画法で次のダイスを振る数を求める
	memset(memo, 0,sizeof(memo));
	memset(memo2,0,sizeof(memo2));
	memo[0]=1;
	int up=max*d;
	for(int i=1;i<=max;i++){
		//振るさいころの数
		for(int j=1;j<=d;j++){
			//さいころの目
			for(int L=up-j;L>=0;L--){
				//さいころの合計数に新しいサイの結果を足す
				memo2[L+j]+=memo[L];
			}
		}
		for(int j=1;j<=up;j++){
			nextMemo[j]+=memo2[j]*multiMemo[i];
		}
		memcpy(memo,memo2,sizeof(memo));
		memset(memo2,0,sizeof(memo2));
	}
}
int main(){
	//4 4*6=24 24*8=192 192*12=2304, 2304*20=46080

calc(6,4,memo4,memo6);//動的計画法で6面ダイスを1個振った場合から4個振った場合までの組み合わせ数をmemo6に代入
	calc(8,24,memo6,memo8);//8面ダイスを1個振った場合から24個振った場合までの組み合わせ数をmemo8に代入
	calc(12,192,memo8,memo12);//以下同じ
	calc(20,2304,memo12,memo20);//20面になると入ってる組み合わせ数が凄いことに、、、
	
	//組み合わせの総数を求める
	__float128 all=0,E=0,ans=0;
	for(int i=1;i<46081;i++){
		all+=memo20[i];
	}
	//20面の全平均を出す
	for(int i=1;i<46081;i++){
		E+=(memo20[i]/all)*i;
	}
	//分散を出す
	for(__float128 i=1;i<46081;i++){
		ans+=(i-E)*(i-E)*memo20[(int)i]/(all);
	}
	//分散ansを出力したいが方法が分からない,,,
	char c[80];
	quadmath_snprintf(c,80,"%.4Qf",ans);//サイト通り記述したのにコンパイルエラーが出てます
}