您的位置:首页 > 运维架构

HDU3853 LOOPS 概率DP数学期望

2019-03-01 14:41 281 查看

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;
因为存在多次先回到自身再向其他方向移动的情况,所以向右或向下移动所消耗的能量和回到自身的次数相关,存在以下关系:
DP[x][y]=lim⁡n→+∞∑i=1n[ai−1⋅b(2i+DP[x][y+1]+ai−1⋅c(2i+DP[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→+∞lim​i=1∑n​[ai−1⋅b(2i+DP[x][y+1]+ai−1⋅c(2i+DP[x+1][y])]
把需要求和的每一项分开,发现是两个同型的等比数列and两个同型等差数列和等比数列的乘积,再分别计算求和得到下面的式子:
DP[x][y]=lim⁡n→+∞[(b⋅DP[x][y+1]+c⋅DP[x+1][y])⋅1−an−11−a+2⋅(1−an1−a−(n−1)⋅an)]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​[(b⋅DP[x][y+1]+c⋅DP[x+1][y])⋅1−a1−an−1​+2⋅(1−a1−an​−(n−1)⋅an)]
∵lim⁡n→+∞1−an−1=lim⁡n→+∞1−an=1          lim⁡n→+∞an=0         lim⁡n→+∞n⋅an=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→+∞lim​1−an−1=n→+∞lim​1−a< 20000 span class="vlist-t">n=1          n→+∞lim​an=0         n→+∞lim​n⋅an=0      (0<=a<1)
∴DP[x][y]=b⋅DP[x][y+1]+c⋅DP[x+1][y]+21−a∴DP[x][y] = \frac{b\cdot DP[x][y+1]+c\cdot DP[x+1][y]+2}{1-a}∴DP[x][y]=1−ab⋅DP[x][y+1]+c⋅DP[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: