这题咕了好久.....
设$f[i][j]$表示从$(i,j)$到最后一行的期望步数;
则有
$ f[i][1]=frac{1}{3}(f[i][1]+f[i][2]+f[i+1][1])+1$
$ f[i][m]=frac{1}{3}(f[i][m]+f[i][m-1]+f[i+1][m])+1$
$ f[i][j]=frac{1}{4}(f[i][j]+f[i][j-1]+f[i][j+1]+f[i+1][j])+1$
所以他有后效性(于是我们疯狂迭代)
然而要高斯消元。。。。
具体的来说,就是把每行的每个转移都写在系数矩阵里,对这一行进行高斯消元;增广矩阵要写已知量;
化简上面的式子:
$frac{2}{3}*f[i][1]-frac{1}{3}*f[i][2]=frac{1}{3}*f[i+1][1]+1 $
$frac{2}{3}*f[i][m]-frac{1}{3}*f[i][m-1]=frac{1}{3}*f[i+1][m]+1$
$frac{3}{4}*f[i][j]-frac{1}{4}*f[i][j-1]-frac{1}{4}*f[i][j+1]=frac{1}{4}*f[i+1][j]+1$
注意,高斯消元消的是某一行,每个位置的值。
又注意到上面的有分数不美观,实际写的时候可以化简(方程两边同乘1个数)。
还有,高斯消元的过程需要简化
深蓝代表系数矩阵中有数的位置,浅灰蓝色为增广矩阵。
先消成这个样子:
然后从最后一行向上代入
#include<cstdio> #include<iostream> #define R register int #define db double using namespace std; inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } int n,m,x,y; db f[1003],a[1003][1003]; inline void init() { a[1][1]=2,a[1][2]=-1,a[1][m+1]=3+f[1]; a[m][m]=2,a[m][m-1]=-1,a[m][m+1]=3+f[m]; for(R i=2;i<m;++i) a[i][i]=3,a[i][i-1]=a[i][i+1]=-1,a[i][m+1]=f[i]+4; } inline void Gauss() { for(R i=1;i<=m;++i) { if(i<m) a[i][i+1]/=a[i][i]; a[i][m+1]/=a[i][i],a[i][i]=1; a[i+1][i+1]-=a[i][i+1]*a[i+1][i]; a[i+1][m+1]-=a[i][m+1]*a[i+1][i],a[i+1][i]=0; } for(R i=m-1;i;--i) a[i][m+1]-=a[i][i+1]*a[i+1][m+1]; for(R i=1;i<=m;++i) f[i]=a[i][m+1]; } signed main() { n=g(),m=g(),x=g(),y=g(); if(m==1) printf("%.10lf ",(db)2*(n-x)); else { for(R i=n-1;i>=x;--i) { init(); Gauss(); } printf("%.10lf ",f[y]); } }
2019.05.24