首页 > 代码库 > HDU 4711 Weather 概率DP
HDU 4711 Weather 概率DP
题意:有个人,他在某个区域待了n天,这个区域有m个地方,有w种天气情况,先给出这个人行程的每天的天气情况,然后给出 从第i个地方到第j个地方的概率,也可以自身到自身,然后给出 某个地方 是某种天气的概率,问你 这个人最优可能的行程路线也就是每天待在哪个地方,
概率DP,求出哪些路线概率最大 再在其中取最小字典序的
假设方程 dp[i][j] 代表 第i天待在j城市,状态转移
dp[i][j] = max(dp[i][j],dp[i - 1][k] * mp[k][j] * pp[j][nnum[i]]);其中mp[i][j]代表由i地方到j地方的概率,pp[j][nnum[i]]代表j这个地方天气为nnum[i]的概率,0<k<m,边界dp[0][0] = 1.00;
然后交了几把发现一直WA,方程没错 觉得是精度问题,因为每次有比较大小的过程,而且乘了2000次,肯定会有误差的,于是改用了long double,但是还是错误,最后还是没做出,后来看题解 发现可以用对数来解决,这高中书白读了....把mp[i][j] 跟pp[i][j]的 概率 取对数 log(mp[i][j]),log(pp[i][j]),这样后面的状态转移方程 乘法就可以写成加法了
dp[i][j] = max(dp[i][j],dp[i - 1][k] + mp[k][j] + pp[j][nnum[i]]);
然后又开始交,发现还是一直WA,因为 mp[i][j]是有可能为0的,意思是 第i个地方不可能到第j个地方,这里要判断一下把 ,若为0 则mp[i][j] = inf,当然 pp[i][j]也有可能为0,在这里判断为是否为0考虑精度问题,我是 判断它是否小于eps, eps 我精确到了 1e-16次都不行,最后直接改成if(mp[i][j] == 0.00)反而就过了,晕死,坑点好多的题目,
int n,m,w; int nnum[1000 + 55]; double dp[1000 + 55][100 + 55]; double mp[100 + 55][100 + 55]; double pp[100 + 55][100 + 55]; int father[1000 + 55][100 + 55]; void init() { memset(father,0,sizeof(father)); } bool input() { while(cin>>n>>m>>w) { for(int i=1;i<=n;i++) cin>>nnum[i]; for(int i=0;i<m;i++) for(int j=0;j<m;j++) { cin>>mp[i][j]; if(mp[i][j] == 0.00) mp[i][j] = -10000000; else mp[i][j] = log(mp[i][j]); } for(int i=0;i<m;i++) for(int j=0;j<w;j++) { cin>>pp[i][j]; if(mp[i][j] == 0.00) mp[i][j] = -10000000; else pp[i][j] = log(pp[i][j]); } return false; } return true; } void dfs(int now,int pos) { if(now == 1) { cout<<pos; return ; } dfs(now - 1,father[now][pos]); cout<<" "<<pos; } void cal() { for(int i=0;i<1000 + 55;i++) for(int j=0;j<100 + 55;j++) dp[i][j] = -10000000; dp[0][0] = (double)0.00;//边界 for(int i=1;i<n + 1;i++) { for(int j=0;j<m;j++) { for(int k=0;k<m;k++) { //double aa = dp[i - 1][k] + mp[k][j] + pp[j][nnum[i]]; //double bb = dp[i][j]; //cout<<aa<<"***"<<endl; //cout<<bb<<"***"<<endl; if(dp[i - 1][k] + mp[k][j] + pp[j][nnum[i]] > dp[i][j]) { dp[i][j] = dp[i - 1][k] + mp[k][j] + pp[j][nnum[i]]; father[i][j] = k; } } } } double p = -10000000; int s; for(int j=0;j<m;j++) { //cout<<dp[n][j]<<endl; if(dp[n][j] > p) { p = dp[n][j]; s = j; //cout<<s<<endl; //printf("%.10lf\n",p); } } dfs(n,s); puts(""); } void output() { } int main() { int t; cin>>t; while(t--) { init(); if(input())return 0; cal(); output(); } return 0; }
HDU 4711 Weather 概率DP