HDU3853 LOOPS 概率DP数学期望

HDU3853 LOOPS 概率DP

题目大意:

给出一个n * m的矩阵,要求从左上角走到右下角,每次移动消耗两点能量,并且每次的移动方向是有概率的(回到自身,往右或者往下)。输入的矩阵中的每个位置有三个数,分别表示回到自身、向右移动、向下移动的概率,三者概率和为1,要求输出从左上角走到右下角需要消耗的能量值的期望。(测试数据可能有点问题,会出现回到自身的概率为1从而导致死循环的情况)

解题思路:

每一个位置到终点的能量消耗期望,和向右或向下移动之后走到的位置开始走到终点消耗的能量期望有关,所以可以用DP来做。由于有一定概率会回到自身,所以就会提升一定难度,不过用数学方法推导一下就好了。

状态转移方程:DP[ i ][ j ] = (posi [ y ] * DP[ i ][ j+1 ] + posi [ z ] * DP[ i+1][ j ] + 2) / (1-posi [ a ])

其中posi [ a ]、posi [ b ]、posi [ c ]分别表示回到自身、到右边的位置、到下面的位置的概率

状态转移方程的推导:
假设当前位置为( x , y )回到自身的概率为a,向右移动的概率为b,向下移动的概率为c
且a + b + c = 1 , a >= 0 , b >= 0 , c >= 0;
因为存在多次先回到自身再向其他方向移动的情况,所以向右或向下移动所消耗的能量和回到自身的次数相关,存在以下关系:
D P [ x ] [ y ] = lim ⁡ n → + ∞ ∑ i = 1 n [ a i − 1 ⋅ b ( 2 i + D P [ x ] [ y + 1 ] + a i − 1 ⋅ c ( 2 i + D P [ x + 1 ] [ y ] ) ] DP[ x ][ y ] = \lim_{n \rightarrow+\infty} \sum_{i=1}^n [a^{i-1}\cdot b(2i+DP[x][y+1]+a^{i-1}\cdot c(2i + DP[x+1][y])] DP[x][y]=n+limi=1n[ai1b(2i+DP[x][y+1]+ai1c(2i+DP[x+1][y])]
把需要求和的每一项分开,发现是两个同型的等比数列and两个同型等差数列和等比数列的乘积,再分别计算求和得到下面的式子:
D P [ x ] [ y ] = lim ⁡ n → + ∞ [ ( b ⋅ D P [ x ] [ y + 1 ] + c ⋅ D P [ x + 1 ] [ y ] ) ⋅ 1 − a n − 1 1 − a + 2 ⋅ ( 1 − a n 1 − a − ( n − 1 ) ⋅ a n ) ] DP[x][y] = \lim_{n \rightarrow+\infty}[(b\cdot DP[x][y+1]+c\cdot DP[x+1][y])\cdot \frac{1-a^{n-1}}{1-a}+2\cdot (\frac{1-a^n}{1-a}-(n-1)\cdot a^n) ] DP[x][y]=n+lim[(bDP[x][y+1]+cDP[x+1][y])1a1an1+2(1a1an(n1)an)]
∵ lim ⁡ n → + ∞ 1 − a n − 1 = lim ⁡ n → + ∞ 1 − a n = 1            lim ⁡ n → + ∞ a n = 0           lim ⁡ n → + ∞ n ⋅ a n = 0        ( 0 &lt; = a &lt; 1 ) ∵ \lim_{n\rightarrow +\infty}1-a^{n-1}= \lim_{n \to+\infty}1-a^n=1 \ \ \ \ \ \ \ \ \ \ \lim_{n\to+\infty}a^n=0\ \ \ \ \ \ \ \ \ \lim_{n\to+\infty}n\cdot a^n=0\ \ \ \ \ \ (0&lt;=a&lt;1) n+lim1an1=n+lim1an=1          n+liman=0         n+limnan=0      (0<=a<1)
∴ D P [ x ] [ y ] = b ⋅ D P [ x ] [ y + 1 ] + c ⋅ D P [ x + 1 ] [ y ] + 2 1 − a ∴DP[x][y] = \frac{b\cdot DP[x][y+1]+c\cdot DP[x+1][y]+2}{1-a} DP[x][y]=1abDP[x][y+1]+cDP[x+1][y]+2

AC代码:
#include<cstdio>
#include<cstring>
using namespace std;
static const int maxn = 1111;
struct Node{
    double x,y,z;
};
int n,m;
struct Node node[maxn][maxn];
double dp[maxn][maxn];
double solve(int x,int y){
    if(x==n&&y==m||x>n||y>m) return 0;
    if(dp[x][y]!=0) return dp[x][y];
    if(node[x][y].x==1) return dp[x][y] = 0;                    //题目数据问题
    return dp[x][y] = (2+node[x][y].y*solve(x,y+1)+node[x][y].z*solve(x+1,y))/(1-node[x][y].x);
}
int main(){
    while(scanf("%d %d",&n,&m)!=EOF){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%lf %lf %lf",&node[i][j].x,&node[i][j].y,&node[i][j].z);
            }
        }
        memset(dp,0,sizeof(dp));
        printf("%.3f\n",solve(1,1));
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值