作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4335810.html
一个例子:
韦小宝使用骰子进行游戏,他有两种骰子一种正常的骰子,还有一种不均匀的骰子,来进行出千。
开始游戏时他有2/5的概率出千。
对于正常的骰子A,每个点出现的概率都是1/6.
对于不均匀的骰子B,5,6两种出现的概率为3/10,其余为1/10.
出千的随机规律如下图所示:
我们观测到的投掷结果为:ob={1,3,4,5,5,6,6,3,2,6}
请判断韦小宝什么时候出千了?
我们可以这样建模 xi 表示第 i 次投掷的骰子的种类, yi 表示第 i 次投掷出的点数, λ 表示各个概率参数。
那么第 t 次使用第 i 种骰子投掷的概率 δt(i) 等于
其实 δt+1(i) 可以由 δt(i) 推倒得出:
其中 αji 表示从第 j 个骰子转移到第 i 个骰子的概率。
βi(yt+1) 表示使用第i个骰子投出点 yt+1 的概率。
从而可以使用上述利用动态规划算法进行逐次递推计算。
得到的结果为:
t | yt | δt(A) | Ψt(A) | δt(B) | Ψt(B) |
1 | 1 | 0.1 | A | 0.04 | A |
2 | 3 | 0.0133333 | A | 0.0036 | B |
3 | 4 | 0.00177778 | A | 0.000324 | B |
4 | 5 | 0.000237037 | A | 0.000106667 | A |
5 | 5 | 3.16049e-05 | A | 2.88e-05 | B |
6 | 6 | 4.21399e-06 | A | 7.776e-06 | B |
7 | 6 | 5.61866e-07 | A | 2.09952e-06 | B |
8 | 3 | 7.49154e-08 | A | 1.88957e-07 | B |
9 | 2 | 9.98872e-09 | A | 1.70061e-08 | B |
10 | 6 | 1.33183e-09 | A | 4.59165e-09 | B |
从而从 Ψt(A) 和 Ψt(B) 中选择 δt() 较大的骰子,从而预测骰子种类序列为:AAAAABBBBB
代码如下所示:
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <string> 5 #include <iostream> 6 using namespace std; 7 double initP[2] = {0.6, 0.4};//骰子A,B的初始概率 8 double transferMatrix[2][2] = {{0.8, 0.2}, {0.1, 0.9}};//骰子之间的转移概率 9 double EmissionP[2][6]={{1/6.0, 1/6.0, 1/6.0, 1/6.0, 1/6.0, 1/6.0},//骰子A的发射概率 10 {0.1, 0.1, 0.1, 0.1, 0.3, 0.3}};//骰子B的发射概率 11 double dp[10][2];//dp[i][j]第i步时,使用第j个骰子的最大概率 12 double dpS[10][2];//dpS[i][j]第i步时,使用第j个骰子,得到的最大概率时,使用的骰子种类, 0->A, 1->B 13 int ob[10] = {1, 3, 4, 5, 5, 6, 6, 3, 2, 6};//观测点数 14 bool diceArray[10];//预测骰子使用序列 15 void Viterbi() 16 { 17 memset(dp,0,sizeof(dp)); 18 memset(dpS,0,sizeof(dpS)); 19 memset(diceArray,0,sizeof(diceArray)); 20 dp[0][0] = initP[0]* EmissionP[0][ob[0]-1]; 21 dp[0][1] = initP[1]* EmissionP[1][ob[0]-1]; 22 for( int i = 1 ; i < 10 ; i++ )//投掷次数 23 { 24 for( int j = 0 ; j < 2 ; j++ )//当前状态 25 { 26 for( int k = 0 ; k < 2 ; k++ )//上一个状态 27 { 28 double tempP = dp[i-1][k] * transferMatrix[k][j] * EmissionP[j][ob[i]-1] ; 29 if( dp[i][j] < tempP ) 30 { 31 dp[i][j] = tempP; 32 dpS[i][j] = k; 33 } 34 } 35 } 36 if( dp[i][0] < dp[i][1] ) 37 { 38 diceArray[i] = dpS[i][1]; 39 } 40 else 41 { 42 diceArray[i] = dpS[i][0]; 43 } 44 } 45 } 46 int main(int argc, char *argv[]) 47 { 48 Viterbi(); 49 cout<<"每步每个状态下的概率和骰子种类:"<<endl; 50 for( int i = 0 ; i < 10 ; i++ ) 51 { 52 for( int j = 0 ; j < 2 ; j++ ) 53 { 54 cout<<dp[i][j]<<" "<<dpS[i][j]<<" "; 55 } 56 cout<<endl; 57 } 58 cout<<"预测骰子种类,0->A, 1->B : "<<endl; 59 for( int i = 0 ; i < 10 ; i++ ) 60 { 61 cout<<diceArray[i]<<" "; 62 } 63 cout<<endl; 64 }