
No.3ベストアンサー
- 回答日時:
こんなカンジになるかしら。
まあ予測精度は知りませんが(笑)。
// ここから
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#define LEN 30000 /* 取り敢えず乱数列は長さ30000とする */
#define SPOTS 7 /* サイコロの面の数(実際は1引いて6) */
int* sequence_gen(void); /* ダミー関数 */
void make_table(int data[], int table[][SPOTS][SPOTS]);
void read(int arg[], size_t n);
int eval(int data[][SPOTS][SPOTS], int arg[]);
int main(void) {
int table[SPOTS][SPOTS][SPOTS] = { { { 0 } } }; /* サイコロの出目を記録する三次元配列 */
int* seq;
int input[2];
srand((unsigned) time(NULL)); /* 乱数の初期化 */
seq = sequence_gen(); /* ダミー関数。ここを置き換える。 */
make_table(seq, table); /* 結果のデータテーブル */
read(input, sizeof(input)/sizeof(input[0]));
printf("次の値の予想値は %d です。\n", eval(table, input));
return 0;
}
/* ダミー関数 sequence_gen */
/* 「ランダムな数字の配列と書きましたが厳密にはランダムに見える不順な数列です。」 */
/* との事なんで、この関数を置き換えて下さい */
int* sequence_gen(void) {
static int seq[LEN];
int i;
for (i = 0; i < LEN; i++)
seq[i] = rand() % 6 + 1;
return seq;
}
/* 三次元配列にデータを記録します */
void make_table(int data[], int table[][SPOTS][SPOTS]) {
int i;
for (i = 2; i < LEN; i++)
table[data[i-2]][data[i-1]][data[i]] += 1;
}
void read(int arg[], size_t n) {
int i;
for (i = 0; i < n; i++) {
printf("1から6までのどれかの値を入力してください : ");
scanf("%d", &arg[i]);
}
}
/* 過去の二回の入力より、結果予測を過去のデータから最大値として探し、出目を返します */
int eval(int data[][SPOTS][SPOTS], int arg[]) {
int* array = data[arg[0]][arg[1]];
int index_max = 0;
int i;
for (i = 1; i < SPOTS; i++) {
if (array[index_max] < array[i])
index_max = i;
}
return index_max;
}
// ここまで
まず、上のコードは、取り敢えず
「ランダムな数字の配列と書きましたが厳密にはランダムに見える不順な数列です。」
との事だったんですが、そのコード自体は知らないんで、取り敢えず、暫定的にC言語の乱数列を使ってコーディングしています。
stdlib.hとtime.hは乱数と乱数の初期化の為に導入してるんですが、その「ランダムに見える」数列の作成方法があるのなら、それらは要らないです。
データ自体が手元にあるのなら、まるっと全部そのへんは置き換えて下さい。
基本的な「確率過程」としての考え方としては、先ほど書いた通り、元々、3つの確率変数A、B、Cがある場合、
P(A, B, C) = P(A)*P(B|A)*P(C|A, B)
って計算を施して、「最大の確率を返せ」と言う問題になります。
ただ、データベースにカウントしてる場合、わざわざ「確率計算」をしなくて良い。
単純に、最大値としてのデータが入ってる場所の「インデックス」を返せば良い、って事ですよね。
また、フツーはマルコフ連鎖で考えて(その方が問題を単純化出来るので)
P(A)*P(B|A)*P(C|A, B) => P(A) * P(B|A) * P(C|B)
として「前項だけが影響を持つ」と言う仮定を施すんですが、さっきの話を聞く限り、「前二項」両者とも影響があり、なおかつ順序が重要なカンジなんで、その考え方にしています。
※ つまり、通常・・・それが「現実に対応するかどうか」はさておき、あくまで計算が単純になる、と言う理由で、例えばさっきの例だと2 -> 5と言う「流れ」と5 -> 2と言う「流れ」は全く同じだ、と考えるのを「好み」ます。
統計は実は「現実をキチンと反映してる」のではなくって、割に、計算単純化の為の「仮定」をポンポン入れて計算する傾向がある、ってのを「押さえておいて」下さい。
「何が仮定なのか」と言うのを忘れると、実は相当マズい分野なのです。
さて、そうすると、コーディングのポイントは何と言っても「配列の扱い」になりますね。
例えば、「乱数列に見える」数列、があるとします。初項から次のような配列があるとしましょう。
3、1、4、1、5、9、2、6、5、3、5、8、9、7、9、3......
さっきの話から言うと、スタートは3番目(Cでのコーディング上は二番目)である4からループをスタートさせるわけです。
3->1->4
当然前二項は3と1です。そしてこの3つの数字の出現をデータに記録しないといけません。
そこで「3次元配列」を用います。
int table[i][j][k]; /* 各要素は0で初期化されてる前提 */
つまり、3次元配列のi行j列のk番目にデータを格納していく、って考え方ですよね。データを格納する、っつーかカウントしていく、って事ですか。
上の例だと3行目1列の4番目に+1する。
次に取り出すデータは
1->4->1
になるんで、1行目4列の1番目のカウンターを1増やす・・・以降与えられた乱数(に見える)列の最後まで延々とこの作業を繰り返します。
こうやってデータテーブルを作成しておいて、あとは入力で、
2->7
とやってきたら、まずは
2行7列目
の配列を取り出します。
コードで言うとeval関数の
int* array = data[arg[0]][arg[1]];
って部分がそれですね。
仮にその配列が
{ 0 : 無視, 1 : 150, 2 : 129, 3 : 128, 4 : 149, 5 : 136, 6 : 138 }
と言う状態だったら、1番目(つまりサイコロで言うと1の目)が最頻出の出目(この例だと150回出てて最多)なんで、1番目、と言う配列のインデックスを返せば題意を満たす、って事になります。
No.2
- 回答日時:
なるほど、って事は入力自体は2回、って事ですかね。
基本的には、例えばその例に従うと
P(2)*P(5|2)*P(X| 5, 2) -> 2が出る確率×2が出た、って条件で5が出る確率×過去二回で2と5が同時に生起した状態でXが出る確率
を計算してその最大値を返せ、って問題に見えるんですが、それで構わない、って事ですかね。
そんな感じです!
あと、数列は入力に従って伸びていくので回数を重ねていけば当たる回数も多くなるのかなと...
友達とサイコロの出る目を当てるプログラムを作って、どちらがより精密に当てれるかを勝負してて、勝ちたいのでお願いします!!
No.1
- 回答日時:
面白い問題ですが、いくつか不明瞭な点があります。
1. 「ランダムな数字の配列」ってのの「数字」は整数でしょうかそれとも実数でしょうか。
2. 「理論的には」あるランダムな数列があって、ある数字の「次の数字」は予測出来ません(予測出来れば「ランダム」と言う前提が壊れます)。
3. 2.の前提で、「敢えての」予測なら、これはマルコフ連鎖前提でしょうか。
4. 「入力された値」と言うのはユーザーからの入力数値ですか。それともまた乱数で数値を生成する前提ですか。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
関数から配列を返すには?
-
配列の要素数に変数を入れたい...
-
c言語
-
define で 配列
-
C#で構造体の配列を持った構造...
-
C言語 ファイルの指定された行...
-
要素数・要素の値が未定の配列...
-
c言語 構造体
-
char gyou[1024];でcharの表現...
-
VB.NETにおける構造体の初期化
-
MFC - ダイアログボックスのPic...
-
Cプログラム 関数化
-
c言語プログラミング 等差数列...
-
C言語で重複組合せを全列挙
-
C言語 数値の連続入力について
-
.NET C++で、構造体の配列をnew...
-
[C++/CLI]マネージコードで配列...
-
MFCのCArrayを使った二次元配列
-
C言語についてです 5人のテスト...
-
C言語の2次元配列 容量が大き...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
関数から配列を返すには?
-
配列の要素数に変数を入れたい...
-
define で 配列
-
C#で構造体の配列を持った構造...
-
コンボボックスでデフォルト値...
-
C#で配列が空かを判定するには?
-
MFC - ダイアログボックスのPic...
-
構造体のextern方法
-
C言語において、 配列要素をひ...
-
C言語の2次元配列 容量が大き...
-
配列のアドレス部
-
配列の配列をmemcpyやmemcmpし...
-
万年カレンダーについて。
-
C言語 ファイルの指定された行...
-
この変数名はわかりにくいですか?
-
MFCのCArrayを使った二次元配列
-
fclose()でセグメンテーション違反
-
c言語
-
C言語の配列のコピーについて
-
マルチスレッド環境での配列使...
おすすめ情報
不明瞭な点について補足です。
・数字は整数です。
・ランダムな数字の配列と書きましたが厳密にはランダムに見える不順な数列です。
・入力はユーザーからの入力数値です。
説明が難しいですが、例えば2という数値に関してその一個前の値が5だった場合に過去のデータから5→2の次にくる値を調べて出てくる頻度の高い値を予測される値として出力するという仕組みです。