题目大意:有一只坏了的机器人站在一个n∗m的网格里,初始位置在(x,y)。现在每个单位时间内它会随机选左右下三个方向走,如果它随机的方向会走出网格就不会往这个方向走。当然这个机器人也可能原地停留一个单位时间。求机器人走到第n行的期望时间。
只能说这题出得太吼辣~
我们用f[i][j]表示从(i,j)这个点走到第n行所需要的期望时间。那么我们显然得到:
f[i][1]=(f[i][1]+f[i][2]+f[i+1][1])/3+1;
f[i][j]=(f[i][j-1]+f[i][j]+f[i][j+1]+f[i+1][j])/4+1; j∈[2,m-1]
f[i][m]=(f[i][m]+f[i][m-1]+f[i+1][m])/3+1;
如果对上述的方程进行simple的高斯消元,很明显是不行的.....
但还是要消一遍先~,得到:
f[i][1]=(3+f[i][2]+f[i+1][1])/2;
f[i][j]=(4+f[i][j+1]+f[i][j-1]+f[i+1][j])/3;
f[i][m]=(3+f[i][m-1]+f[i+1][m])/2;
不妨设f[i+1]是已知的,那么,我们对该式子做一些细微调整。
以f[i][1]举例 f[i][1] = (3+f[i][2]+f[i+1][1])/2 = (3+f[i+1][1])/3+1/2f[i][2]。
我们设(3+f[i+1][1])/3为A,1/2为B。
则f[i][2]= (4+f[i][3]+f[i][1]+f[i+1][j])/3 = (4+f[i][3]+A+B*f[i][2]+f[i+1][2])/3
化简后得到 f[i][2]=(4+f[i][3]+A+f[i+1][2])/(3-B)。
与化简f[1]的方式相同,将f[i][2]化为A+Bf[i+3],不难得到F[i][2]=(4+A+f[i+1][2])/(3-B) + 1/(3-B)*f[i][3],即A’=(4+A+C)/(3-B),B'=1/(3-B)。 f[i][3...m-1]的推法与f[i][2]相同。(C为f[i+1][2])
下面考虑f[i][m],在此之前,我们已经求得f[i][m-1]=A+B*f[i][m]。 通过前面的推论我们得知:f[i][m]=(3+f[i][m-1]+f[i+1][m])/2,代入后得到f[i][m]=(3+A+B*f[i][m]+f[i+1][m])/2。
化简后得到f[i][m]=(3+A+f[i+1][m])/(2-B)。f[i][m]的准确值终于被求出来了.....,由于先前的f[i][j]均推出了f[i][j]=A+B*f[i][j+1],所以该行的所有f值将全部求出。
这一过程重复n-x+1次即可。时间复杂度为O((n-x+1)*m)。
本题有个小坑:当m=1时,上文描述的转移无效,此情况下转移为f[i][1]=f[i+1][1]+2。(我就是忘记加这个特判所以没有1A)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define M 1010 5 using namespace std; 6 double f[M][M]={0},a[M]={0},b[M]={0}; 7 8 int main(){ 9 int n,m,x,y; scanf("%d%d%d%d",&n,&m,&x,&y); 10 n=n-x+1; if(m==1) f[1][y]=(n-1)*2; 11 else 12 for(int i=n-1;i;i--){ 13 memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); 14 a[1]=(3+f[i+1][1])/2.; b[1]=1./2.; 15 for(int j=2;j<m;j++){ 16 double c=f[i+1][j]; 17 a[j]=(4.+a[j-1]+c)/(3-b[j-1]); 18 b[j]=1./(3-b[j-1]); 19 } 20 f[i][m]=(3.+a[m-1]+f[i+1][m])/(2.-b[m-1]); 21 for(int j=m-1;j;j--){ 22 f[i][j]=a[j]+b[j]*f[i][j+1]; 23 } 24 } 25 printf("%.10lf ",f[1][y]); 26 }