您的位置:首页 > 其它

HDOJ 4865 Peter's Hobby(概率dp, viterbi)

2017-07-06 00:02 387 查看
原题链接

题目描述

题目大意

给定不同天气的湿度概率矩阵,以及不同天气的状态转移矩阵。输入湿度序列,求此湿度序列所对应的最有可能的天气序列。

题目分析

一道典型的概率dp题,或者叫viterbi算法。viterbi算法常用在HMM(隐马尔科夫模型)的三个基本问题中的问题二:decoding,即Given an observation sequence and an HMM, determine the most probable hidden state sequence。

本题中,湿度是直接可观测的,隐藏的状态就是天气状态。(不过这里不太合适,天气状态也是可观测的)。

这里引入viterbi,是为了更形象的说明期间的涉及到的概率问题,并不是是说此题就是viterbi算法了。因为viterbi本质就是DP,除了HMM的decoding,还可以用在其他地方。

说了这么多,简单描述下viterbi算法。



式中,Vt(j)就表明在第t天天气状态为j(晴天,雨天,阴天)的概率。我们求得最后一天VT(j)的概率,选取最大值,然后根据btt(j)回溯每一天的天气状况。

aij, 天气状态转移概率;

bj(xt), emission matrix(发射矩阵),天气为j湿度为xt的概率。

这两个概率矩阵就是题目提供的两个概率矩阵。

这里说得比较浅陋,如果第一次接触,可能比较难懂,直接看代码吧。代码中为了把乘法转化为加法,利用了log。

AC代码

#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <string>
#include <cmath>
#include <cstring>
using namespace std;

double a[3][3] = {0.5, 0.375, 0.125,
0.25, 0.125, 0.625,
0.25, 0.375, 0.375};   // transition probability

double b[3][4] = {0.6, 0.2, 0.15, 0.05,
0.25, 0.3, 0.2, 0.25,
0.05, 0.10, 0.35, 0.50}; // emittion probability
double dp[55][3];   // results
int path[55][3]; // path of days
int in[55];         // input, the humidity of leaves

int solve(string leaves) {
if (leaves == "Dry") return 0;
if (leaves == "Dryish") return 1;
if (leaves == "Damp") return 2;
if (leaves == "Soggy") return 3;
return -1;
}

string solve(int days) {
if (days == 0) return "Sunny";
if (days == 1) return "Cloudy";
if (days == 2) return "Rainy";
return nullptr;
}

void print(stack<int> sta, int count) {
//cout << "Case #" << count << endl;
printf("Case #%d:\n", count);
while (!sta.empty()) {
int val = sta.top();
cout << solve(val) << endl;
sta.pop();
}
}

void init() {
dp[0][0] = log(0.63 * b[0][in[0]]);
dp[0][1] = log(0.17 * b[1][in[0]]);
dp[0][2] = log(0.2 * b[2][in[0]]);
}

int main() {

int T, N, count = 0;
cin >> T;
while (T--) {
count++;
cin >> N;
for (int i = 0; i < N; ++i) {
string leaves; cin >> leaves;
in[i] = solve(leaves);
}

init();   // init the fisrt day.
for (int i = 1; i < N; ++i) {
for (int j = 0; j < 3; j++) {
double tmp = dp[i - 1][0<
4000
/span>] + log(a[0][j] * b[j][in[i]]);
path[i][j] = 0;
for (int k = 1; k < 3; ++k) {
if (dp[i - 1][k] + log(a[k][j] * b[j][in[i]]) > tmp) {
tmp = dp[i - 1][k] + log(a[k][j] * b[j][in[i]]);
path[i][j] = k;
}

}
dp[i][j] = tmp;
}
}

double maxP = dp[N-1][0];
int maxN = 0;
for (int i = 1; i < 3; i++) {
if (dp[N-1][i] > maxP) {
maxP = dp[N-1][i];
maxN = i;
}
}

stack<int> sta; sta.push(maxN);
for (int i = N - 1; i > 0; --i) {
sta.push(path[i][maxN]);
maxN = path[i][maxN];
}

print(sta, count);

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  概率dp viterbi