题目链接:http://codeforces.com/problemset/problem/24/D;
题目大意:给出 n*m 的方格地图,机器人在 (x, y),机器人只能向下,向左,向右走,当达到边界时不能走,问到达最后一行需要的期望;
思路:
有两种思路,一个是通过多重的循环精确答案,另一个是找到递推式;
首先对于一个不再边界的点 (i, j),从这里到最后一行需要的期望是由周围决定的;
如果m=1: dp[i][1] = 1/2 * dp[i + 1][1] + 1/2 * dp[i][1] +1;
如果 j==1 : dp[i][1] = 1/3 * dp[i + 1][1] + 1/3 * dp[i][2] + 1/3 * dp[i][1] + 1
如果 j==m :dp[i][m] = 1/3 * dp[i + 1][m] + 1/3 * dp[i][m - 1] + 1/3 * dp[i][m] + 1
否则 : dp[i][j] = 1/4 * dp[i + 1][j] + 1/4 * dp[i][j - 1] + 1/4 * dp[i][j] + 1/4 * dp[i][j + 1] + 1
第一种思路(递推式):
首先化简j==1情况的递推式为: dp[i][1] = 1/2 * (3 + dp[i + 1][1]) + 1/2 * dp[i][2]. 这个式子中dp[ i +1][1]是已知的,但是dp[ i][2]是不确定的,所以可以设 常数A=1/2*(3*dp[ i+1][1]),常数B=1/2,dp[ i][1] = A+B*dp[ i][2];
继续化简 dp[i][2] = (4 + A + dp[i + 1][2]) / 3 - B + dp[i][3] / (3 - B);
可以设 A’=(4 + A + dp[i + 1][2]) / 3 - B ,设 B’ = 1 / (3 - B) ; 原式子变成式子变为dp[i][2] = A’ + B’ * dp[i][3];
同理,dp[ i][m-1]=A(m-1)+B(m-1)*dp[i][m];
dp[i][m]=(3+A(m−1)+dp[i+1][m])/(2−B(m−1));
AC代码:
#include<cstring>
#include<string>
#include<cstdio>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<set>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e3+10;
double dp[N][N];
double a[N],b[N];
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
memset(dp,0,sizeof(dp));
int x,y;
scanf("%d %d",&x,&y);
if(m==1)//注意m=1时,公式不一样,直接能求出答案
{
printf("%.10lf\n",2.0*(n-x));
continue;
}
for(int i=1;i<=m;++i)
dp[n][i]=0.0;
for(int i=n-1;i>=1;i--)
{
a[1]=(3.0+dp[i+1][1])/2.0;
b[1]=1.0/2;
for(int j=2;j<m;j++)
{
a[j]=(4+a[j-1]+dp[i+1][j])/(3-b[j-1]);
b[j]=1.0/(3.0-b[j-1]);
}
dp[i][m]=(3+a[m-1]+dp[i+1][m])/(2-b[m-1]);
for(int j=m-1;j>=1;j--)
{
dp[i][j]=a[j]+b[j]*dp[i][j+1];
}
}
printf("%.10lf\n",dp[x][y]);
}
return 0;
}
第二种:
首先化简j==1情况的递推式为: dp[i][1] = 1/2 * (3 + dp[i + 1][1]) + 1/2 * dp[i][2]. 这个式子中dp[ i +1][1]是已知的,但是dp[ i][2]是不确定的,但是我们可以多循环就此这个步骤,答案就能精确了;
AC代码:
//#include<bits/stdc++.h>
#include<cstring>
#include<string>
#include<cstdio>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<set>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e3+10;
double dp[N][N];
double a[N],b[N];
int main()
{
int n,m,x,y;
while(~scanf("%d %d %d %d",&n,&m,&x,&y))
{
memset(dp,0,sizeof(dp));
for(int i=n-1;i>=1;i--)
{
for(int t=1;t<=100;++t)
{
for(int j=1;j<=m;++j)
{
if(m==1)
dp[i][j]=dp[i+1][j]+2.0;
else if(j==1)
dp[i][j]=(dp[i+1][j]+dp[i][j+1]+3)/2.0;
else if(j==m)
dp[i][j]=(dp[i+1][j]+dp[i][j-1]+3)/2.0;
else
dp[i][j]=(dp[i+1][j]+dp[i][j-1]+dp[i][j+1]+4)/3.0;
}
}
}
printf("%.10lf\n",dp[x][y]);
}
return 0;
}