HDU3853 LOOPS 期望DP基础题

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3853
题目大意(只是大意,名字什么的可能和原题描述不一样~):

爱丽丝与华容道

题目描述

爱丽丝是一个魔法师。
爱丽丝想要帮助她的朋友爱迪生拯救这个世界。但是她现在被困在了一个叫做“华容道”的迷宫中。
华容道是一个由R*C个格子组成的矩形,他有R行,每一行有C列格子。除了出口格子外,每个格子都有一个传送门。爱丽丝每开一次传送门需要消耗2颗魔力豆。我们假设现在爱丽丝在格子(r,c)上,那么当爱丽丝使用了2颗魔力豆打开传送门并且进入传送门之后,这个传送门可能会将她传送到下方的格子(r+1,c)上,也有可能将他传送到右侧的格子(r,c+1)上,当然咯,这个传送门也有一定的概率传送失败,如果传送失败,那么爱丽丝还是会返回当前的格子(r,c)上。
在一开始,爱丽丝在华容道的左上角(1,1)处,而华容道的出口在右下角(R,C)处。你的任务是帮助爱丽丝计算他到达出口时消耗魔力豆的期望数量,以帮助她提前了解她是否具有足够的魔力豆来拯救世界。

输入

输入的第一行包含两个正数R和C(2<=R,C<=1000)。
接下来有R行数据,每行有C*3个实数(这些实数都会精确到小数点后两位),每三个数为一组。第r行的第c组的三个数分别表示从(r,c)到(r,c),(r,c+1),(r+1,c)的概率。同一行的每组数据之间有4个空格分隔。
输入数据保证每组的三个数相加等于1,最右边的组的第二个数为0(因为最右边的格子没有办法再往右了),最后一行的各组的第三个数为0(因为最下面的格子没有办法再往下了)。
你可以忽略右下角那组输入数据。他们的出现仅仅是为了输入数据的格式看上去比较整齐而已。
对于所有的数据,答案都保证不会超过1000000。

输出

输出一个实数,保留三位小数位,表示魔法师爱丽丝逃离华容道德期望消耗魔力豆数量。

样例输入

2 2
0.00 0.50 0.50    0.50 0.00 0.50
0.50 0.50 0.00    1.00 0.00 0.00

样例输出

6.000

题目分析

我们假设 dp[i][j] 表示从(i,j)到达(R,C)的期望魔力豆数,则 dp[R][C]=0 ,我们需要求解的就是 dp[1][1]
我们设 p0[i][j] 表示(i,j)留在原地的概率, p1[i][j] 表示(i,j)到达(i,j+1)的概率, p2[i][j] 表示(i,j)到达(i+1,j)的概率,那么我们可以这么想:
爱丽丝消耗了2颗魔力豆:

  • 她可能有 p[i][j] 的概率留在原地,所以 (i,j)-->(i,j) 的情况下的期望组成部分为:
p0[i][j] * (dp[i][j] + 2)
  • 她可能有 p1[i][j] 的概率到达右边的格子,所以 (i,j)-->(i,j+1) 的情况下的期望组成部分为:
p1[i][j] * (dp[i][j+1] + 2)
  • 她可能有 p2[i][j] 的概率到达下方的格子,所以 (i,j)-->(i+1,j) 的情况下的期望组成部分为:
p2[i][j] * (dp[i+1][j] + 2)

如上3部分相加就得到了实际的期望的公式:

dp[i][j] = p0[i][j] * (dp[i][j] + 2) + p1[i][j] * (dp[i][j+1] + 2) + p2[i][j] * (dp[i+1][j] + 2)
= p0[i][j] * dp[i][j] + p1[i][j] * dp[i][j+1] + p2[i][j] * dp[i+1][j] + 2

进一步推导得到:

dp[i][j] = (p1[i][j] * dp[i][j+1] + p2[i][j] * dp[i+1][j] + 2) / (1 - p0[i][j])

可能存在一种情况是 p0[i][j] == 1 ,这种情况等于说当你到达这个点以后你就出不来了,虽然题目意思中保证了我们能够顺利到达(R,C)节点,但是它并没有保证我们在进入另外的那些点我们进去了就出不来了的情况出现。

示例代码:

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
#define EPS 1e-6
const int maxn = 1010;

int R, C;
double p0[maxn][maxn], p1[maxn][maxn], p2[maxn][maxn], dp[maxn][maxn];

int main() {
    while (~scanf("%d%d", &R, &C)) {
        for (int i = 1; i <= R; i ++) {
            for (int j = 1; j <= C; j ++) {
                scanf("%lf%lf%lf", &p0[i][j], &p1[i][j], &p2[i][j]);
            }
        }
        dp[R][C] = 0;
        for (int i = R; i >= 1; i --) {
            for (int j = C; j >= 1; j --) {
                if (i == R && j == C) continue;
                if (fabs(1 - p0[i][j]) < EPS) continue;
                dp[i][j] = (p1[i][j] * dp[i][j+1] + p2[i][j] * dp[i+1][j] + 2) / (1 - p0[i][j]);
            }
        }
        printf("%.3lf\n", dp[1][1]);
    }
    return 0;
}

注意:这道题目有点卡数据,用cin会超时。

参考链接:https://www.cnblogs.com/kuangbin/archive/2012/10/03/2711140.html

posted @ 2019-04-16 11:32  zifeiy  阅读(169)  评论(0编辑  收藏  举报