[HDOJ 4865] Peter's Hobby [概率DP]

来源:互联网 发布:unity javascript 编辑:程序博客网 时间:2024/05/08 23:13

已知第一天的天气的概率,根据今天的天气可以知道下一天的天气的概率,根据当天的天气可以知道当天的叶子湿度的概率。

现给你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;}

0 0