2019.3.31网易游戏数据挖掘(算法US)笔试编程题第二题题解---HMM

因为考试中没有截图下来,所有只能说个大致的题意。

第一题是一题SQL语句转编程语言。如果拿了70分的话应该是没考虑group by 和之后的去重。如果拿了80分的话是没有考虑到需要size>0。

 

第二题其实是一题HMM,通过HMM前向算法就可以做出来。前向算法本质上属于动态规划的算法,也可以用DP去做。

 

第三题要自己根据题目给出的公式计算梯度。

 

第二题的思路其实和刘建平Pinard博客中的盒子与球的例子是一模一样的,这里转载下博客中关于这部分的内容,完整的博客请见:https://www.cnblogs.com/pinard/p/6955871.html

以及和HMM相关的四讲:

 

              隐马尔科夫模型HMM(一)HMM模型

              隐马尔科夫模型HMM(二)前向后向算法评估观察序列概率

              隐马尔科夫模型HMM(三)鲍姆-韦尔奇算法求解HMM参数

              隐马尔科夫模型HMM(四)维特比算法解码隐藏状态序列

 

这里我们用隐马尔科夫模型HMM(一)HMM模型中盒子与球的例子来显示前向概率的计算。

我们的观察集合是:

V={红,白},M=2

 我们的状态集合是:

Q={盒子1,盒子2,盒子3},N=3

而观察序列和状态序列的长度为3.

初始状态分布为:

\Pi = (0.2,0.4,0.4)^T

状态转移概率分布矩阵为:

A = \left( \begin{array} {ccc} 0.5 & 0.2 & 0.3 \\ 0.3 & 0.5 & 0.2 \\ 0.2 & 0.3 &0.5 \end{array} \right)

 观测状态概率矩阵为:

B = \left( \begin{array} {ccc} 0.5 & 0.5 \\ 0.4 & 0.6 \\ 0.7 & 0.3 \end{array} \right)

球的颜色的观测序列:

O={红,白,红}

 

 

按照前向算法。首先计算时刻1三个状态的前向概率:

时刻1是红色球,隐藏状态是盒子1的概率为:

\alpha_1(1) = \pi_1b_1(o_1) = 0.2 \times 0.5 = 0.1

隐藏状态是盒子2的概率为:

\alpha_1(2) = \pi_2b_2(o_1) = 0.4 \times 0.4 = 0.16

隐藏状态是盒子3的概率为:

\alpha_1(3) = \pi_3b_3(o_1) = 0.4 \times 0.7 = 0.28

 

 

现在我们可以开始递推了,首先递推时刻2三个状态的前向概率:

时刻2是白色球,隐藏状态是盒子1的概率为:

\alpha_2(1) = \Big[\sum\limits_{i=1}^3\alpha_1(i)a_{i1}\Big]b_1(o_2) = [0.1*0.5+0.16*0.3+0.28*0.2 ] \times 0.5 = 0.077

隐藏状态是盒子2的概率为:

\small \alpha_2(2) = \Big[\sum\limits_{i=1}^3\alpha_1(i)a_{i2}\Big]b_2(o_2) = [0.1*0.2+0.16*0.5+0.28*0.3 ] \times 0.6 = 0.1104

隐藏状态是盒子3的概率为:

\small \alpha_2(3) = \Big[\sum\limits_{i=1}^3\alpha_1(i)a_{i3}\Big]b_3(o_2) = [0.1*0.3+0.16*0.2+0.28*0.5 ] \times 0.3 = 0.0606

 

 

继续递推,现在我们递推时刻3三个状态的前向概率:

时刻3是红色球,隐藏状态是盒子1的概率为:

\alpha_3(1) = \Big[\sum\limits_{i=1}^3\alpha_2(i)a_{i1}\Big]b_1(o_3) = [0.077*0.5+0.1104*0.3+0.0606*0.2 ] \times 0.5 = 0.04187

隐藏状态是盒子2的概率为:

\alpha_3(2) = \Big[\sum\limits_{i=1}^3\alpha_2(i)a_{i2}\Big]b_2(o_3) = [0.077*0.2+0.1104*0.5+0.0606*0.3 ] \times 0.4 = 0.03551

隐藏状态是盒子3的概率为:

\alpha_3(3) = \Big[\sum\limits_{i=1}^3\alpha_3(i)a_{i3}\Big]b_3(o_3) = [0.077*0.3+0.1104*0.2+0.0606*0.5 ] \times 0.7 = 0.05284

最终我们求出观测序列:O={红,白,红}的概率为:

P(O|\lambda) = \sum\limits_{i=1}^3\alpha_3(i) = 0.13022

 

 

 

 

按照盒子与球的例子,其实笔试中的第二题思路是一样的。

测试用例如下:


 

输入:

0.4    0.3    0.2    0.1    
0.5    0.2    0.2    0.1    
0.1    0.4    0.1    0.4    
0.3    0.1    0.3    0.3    
0.2    0.4    0.2    0.2    
0.05    0.10    0.20    0.30    0.35
0.08    0.15    0.25    0.35    0.17
0.15    0.25    0.30    0.20    0.10
0.20    0.40    0.20    0.15    0.05
D    B    B    A   

输出:

-2.5928

 

 

 

代码:

//
// Created by Ginray on 2019/3/31.
//

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <iostream>
# include <set>
# include <map>

using namespace std;

int main() {
    double a, b, c, d;
    double data[5][5];
    double reward[5][5];

    scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++)
            scanf("%lf", &data[i][j]);
    }
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 5; j++)
            scanf("%lf", &reward[i][j]);
    }

    char now[50];

    long double ans = 0;
    while (scanf("%s", &now) != EOF) {

        int position;
        if (strcmp(now, "S") == 0)
            position = 0;
        else if (strcmp(now, "A") == 0)
            position = 1;
        else if (strcmp(now, "B") == 0)
            position = 2;
        else if (strcmp(now, "C") == 0)
            position = 3;
        else if (strcmp(now, "D") == 0)
            position = 4;

        a = a * reward[0][position];
        b = b * reward[1][position];
        c = c * reward[2][position];
        d = d * reward[3][position];


        double new_a = a * data[0][0] + b * data[1][0] + c * data[2][0] + d * data[3][0];
        double new_b = a * data[0][1] + b * data[1][1] + c * data[2][1] + d * data[3][1];
        double new_c = a * data[0][2] + b * data[1][2] + c * data[2][2] + d * data[3][2];
        double new_d = a * data[0][3] + b * data[1][3] + c * data[2][3] + d * data[3][3];


        a = new_a;
        b = new_b;
        c = new_c;
        d = new_d;

        ans = a + b + c + d;

//        printf("%.4Lf\n", ans);
//        printf("%.4Lf\n", log10(ans));
    }

    ans = log10(ans);
    printf("%.4Lf\n", ans);

}

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值