题意:
在一个 n ∗ m n*m n∗m的方格上,一个人位于坐标 ( x , y ) (x,y) (x,y)上。在每一个格子等概率的、随机的停在原地,向左移动,向右移动,向下移动。问机器人到最后一行的期望步数多少。
题解:
期望dp。令 d p [ i ] [ j ] dp[i][j] dp[i][j]作为 ( i , j ) (i,j) (i,j)到最后一行的期望步数。期望dp,一般状态的表示都是从后往前,不用 d p [ i ] [ j ] dp[i][j] dp[i][j]作为 ( x , y ) (x,y) (x,y)到 ( i , j ) (i,j) (i,j)的期望步数:
- 终点的状态便于表示
- 对于本题这样多个终点,还需要求 ( x , y ) (x,y) (x,y)到每个终点的概率
推式子还是从前往后推:
j = 1 , d p [ i ] [ j ] = 1 3 ( d p [ i ] [ j ] + d p [ i + 1 ] [ j ] + d p [ i ] [ j + 1 ] ) + 1 1 < j < m , d p [ i ] [ j ] = 1 4 ( d p [ i ] [ j − 1 ] + d p [ i ] [ j ] + d p [ i + 1 ] [ j ] + d p [ i ] [ j + 1 ] ) + 1 j = m , d p [ i ] [ j ] = 1 3 ( d p [ i ] [ j ] + d p [ i + 1 ] [ j ] + d p [ i ] [ j − 1 ] ) + 1 j=1,\ dp[i][j]=\frac{1}{3}(dp[i][j]+dp[i+1][j]+dp[i][j+1])+1\\ 1<j<m, \ dp[i][j]=\frac{1}{4}(dp[i][j-1]+dp[i][j]+dp[i+1][j]+dp[i][j+1])+1\\ j=m,\ dp[i][j]=\frac{1}{3}(dp[i][j]+dp[i+1][j]+dp[i][j-1])+1 j=1, dp[i][j]=31(dp[i][j]+dp[i+1][j]+dp[i][j+1])+11<j<m, dp[i][j]=41(dp[i][j−1]+dp[i][j]+dp[i+1][j]+dp[i][j+1])+1j=m, dp[i][j]=31(dp[i][j]+dp[i+1][j]+dp[i][j−1])+1
因为可以横向移动,所以一行会有m个等式,m个未知数,形成m个方程。想到线性方程组。
显然可以转换线性方程组,以 m = 5 m=5 m=5的线性方程组矩阵 F [ m ] [ m + 1 ] F[m][m+1] F[m][m+1]为例:
[ 2 3 − 1 3 0 0 0 1 3 d p [ i + 1 ] [ 1 ] + 1 − 1 4 3 4 − 1 4 0 0 1 4 d p [ i + 1 ] [ 2 ] + 1 0 − 1 4 3 4 − 1 4 0 1 4 d p [ i + 1 ] [ 3 ] + 1 0 0 − 1 4 3 4 − 1 4 1 4 d p [ i + 1 ] [ 4 ] + 1 0 0 0 2 3 − 1 3 1 3 d p [ i + 1 ] [ 5 ] + 1 ] \begin{bmatrix} \frac{2}{3} & -\frac{1}{3} & 0 & 0&0&\frac{1}{3}dp[i+1][1]+1 \\ -\frac{1}{4}& \frac{3}{4} & -\frac{1}{4}&0&0 &\frac{1}{4}dp[i+1][2]+1\\ 0&-\frac{1}{4}& \frac{3}{4} & -\frac{1}{4}&0 &\frac{1}{4}dp[i+1][3]+1\\ 0&0&-\frac{1}{4}& \frac{3}{4} & -\frac{1}{4}&\frac{1}{4}dp[i+1][4]+1\\ 0&0&0&\frac{2}{3} & -\frac{1}{3}&\frac{1}{3}dp[i+1][5]+1 \end{bmatrix} ⎣⎢⎢⎢⎢⎡32−41000−3143−41000−4143−41000−414332000−41−3131dp[i+1][1]+141dp[i+1][2]+141dp[i+1][3]+141dp[i+1][4]+131dp[i+1][5]+1⎦⎥⎥⎥⎥⎤
可以观察到,只有对角线和两侧有数,所以不需要高斯消元,暴力模拟即可。
自底向上,使 F [ j − 1 ] [ j ] F[j-1][j] F[j−1][j]都变成0;自顶向下,使 F [ j + 1 ] [ j ] F[j+1][j] F[j+1][j]都变成0。
O ( n m ) O(nm) O(nm)完成消元,这样只剩下 F [ j ] [ j ] ≠ 0 F[j][j]\neq 0 F[j][j]=0,求解方程即可。
初始化 ∀ i ∈ [ 1 , m ] , d p [ n ] [ i ] = 0 {\forall}i\in[1,m],dp[n][i]=0 ∀i∈[1,m],dp[n][i]=0。
构造矩阵,求解,得到 d p [ n − 1 ] dp[n-1] dp[n−1]。
依次,得到 d p [ 1 ] dp[1] dp[1]。输出 d p [ x ] [ y ] dp[x][y] dp[x][y]即可。
特判m=1的情况!
个人认为这是一道很好的DP套高斯消元的题。对于当图上可以横向和向下移动时,是一个很优秀的解法。当DP过程中出现循环的时候,有很好的借鉴意义。
AC代码:
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--)
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fir first
#define sec second
#define All(x) x.begin(),x.end()
#define ms(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define INFF 0x3f3f3f3f3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--)
using namespace std;
typedef long long ll;
typedef double db;
const int N=1e3+5;
const int mod=10007;
const db eps=1e-6;
const db pi=acos(-1.0);
int n,m,x,y;
db f[N][N],dp[N][N];
int main(){
#ifndef ONLINE_JUDGE
freopen("D:\\work\\data.in","r",stdin);
#endif
cin>>n>>m>>x>>y;
if(m==1){
printf("%.10lf",2.0*(n-x));
return 0;
}
lep(i,n-1,1){
f[1][1]=f[m][m]=2.0/3;
f[1][2]=f[m][m-1]=-1.0/3;
rep(j,2,m-1) f[j][j]=3.0/4,f[j][j-1]=f[j][j+1]=-1.0/4;
f[1][m+1]=dp[i+1][1]/3+1;
f[m][m+1]=dp[i+1][m]/3+1;
rep(j,2,m-1) f[j][m+1]=dp[i+1][j]/4+1;
lep(j,m,2){
db k=f[j-1][j]/f[j][j];
f[j-1][j-1]-=k*f[j][j-1];
f[j-1][j]-=k*f[j][j];
f[j-1][m+1]-=k*f[j][m+1];
}
rep(j,1,m-1){
db k=f[j+1][j]/f[j][j];
f[j+1][j]-=k*f[j][j];
f[j+1][m+1]-=k*f[j][m+1];
}
rep(j,1,m) dp[i][j]=f[j][m+1]/f[j][j];
}
printf("%.10lf",dp[x][y]);
}