已知第一天的天气的概率,根据今天的天气可以知道下一天的天气的概率,根据当天的天气可以知道当天的叶子湿度的概率。
现给你n天的叶子湿度,求一个最可能的天气序列。
定义状态dp[i][j]为前i天,叶子序列为题目给出条件下的概率
则dp[i][j]=max{dp[i][k]*a[k][j]*b[j][l]},其中a[k][j]表示前一天天气为k的条件下,今天天气为j的概率,b[j][l]表示当天天气为j的条件下,当天叶子湿度为l的概率,l为题目给出。
实际由于数字可能太小趋近于0,所以使用log来防止精度丢失
#include <cstdio>
#include <cstring>
#include <cmath>
double aa[3][4]={
{0.6,0.2,0.15,0.05},
{0.25,0.3,0.2,0.25},
{0.05,0.1,0.35,0.5} };
double bb[3][3]={
{0.5,0.375,0.125},
{0.25,0.125,0.625},
{0.25,0.375,0.375} };
double sstart[3]={0.63,0.17,0.2};
double start[3];
double a[3][4];
double b[3][3];
char weather[3][10]={"Sunny","Cloudy","Rainy"};
int n;
double dp[50][3];
int leaf[50];
int ans[50];
int from[50][3];
int leaftoint(char s[]) {
if (s[0]=='S') return 3;
if (s[1]=='a') return 2;
if (s[3]=='\0') return 0;
return 1;
}
int main() {
int t,tt,i,j,k;
char s[10];
scanf("%d",&t);
for (i=0;i<3;i++)
for (j=0;j<4;j++)
a[i][j]=log(aa[i][j]);
for (i=0;i<3;i++)
for (j=0;j<3;j++)
b[i][j]=log(bb[i][j]);
for (i=0;i<3;i++)
start[i]=log(sstart[i]);
for (tt=1;tt<=t;tt++) {
scanf("%d",&n);
for (i=0;i<n;i++) {
scanf("%s",s);
leaf[i]=leaftoint(s);
}
memset(from,-1,sizeof(from));
dp[0][0]=start[0]+a[0][leaf[0]];
dp[0][1]=start[1]+a[1][leaf[0]];
dp[0][2]=start[2]+a[2][leaf[0]];
for (i=1;i<n;i++) {
for (j=0;j<3;j++) {
for (k=0;k<3;k++) {
double tmp=dp[i-1][k]+b[k][j]+a[j][leaf[i]];
//printf("%d %d %d %lf %lf\n",i,j,k,tmp,dp[i][j]);
//printf("== %lf*%lf*%lf\n",dp[i-1][k],bb[k][j],aa[j][leaf[i]]);
if (from[i][j]==-1||dp[i][j]<tmp) {
from[i][j]=k;
dp[i][j]=tmp;
}
}
}
}
if (dp[n-1][0]>dp[n-1][1]&&dp[n-1][0]>dp[n-1][2]) ans[n-1]=0;
else if (dp[n-1][1]>dp[n-1][2]) ans[n-1]=1;
else ans[n-1]=2;
for (i=n-1;i>0;i--) {
ans[i-1]=from[i][ans[i]];
}
printf("Case #%d:\n",tt);
for (i=0;i<n;i++) {
printf("%s\n",weather[ans[i]]);
}
}
return 0;
}