题意:在n*m的网格上,有一个机器人从(x,y)出发,每次等概率的向右、向左、向下走一步或者留在原地,在最左边时不能向右走,最右边时不能像左走。问走到最后一行的期望。
思路:显然倒着算期望。
我们考虑既不是最后一行,也不靠边的一般方格,设$f[i][j]$为(i,j)这个格子的期望步数,显然有
$f[i][j]=frac{1}{4}*(f[i][j-1]+f[i][j+1]+f[i+1][j]+f[i][j])+1$
移项有:$f[i][j]=frac{1}{3}(f[i][j-1]+f[i][j+1]+f[i+1][j])+frac{4}{3}$。
在我们处理处第i+1行所有的情况时,对于第i行,我们能得到像上述一样m个方程m个未知数,所以可以用高斯消元来解。
但是朴素的高斯消元是$n^3$的,显然会T,但是我们考虑此题的所有方程,写成行列式,会发现这个行列式只有对角线,和与对角线相邻的两行是有值的,这样按初中数学知识,就可以用$O(m)$的解除方程的解。
注意特别m=1的情况即可。
#pragma GCC optimize (2) #pragma G++ optimize (2) #pragma comment(linker, "/STACK:102400000,102400000") #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,b,a) for(int i=b;i>=a;i--) #define clr(a,b) memset(a,b,sizeof(a)) #define pb push_back #define pii pair<int,int > using namespace std; typedef long long ll; ll rd() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=1010; double a[maxn][maxn],f[maxn][maxn],x[maxn]; int n,m,xx,yy; void gauss(int id){ for(int i=1;i<=m;i++){ double tmp=1/a[i][i]; a[i][i]*=tmp; x[i]*=tmp; if(i==m)break; a[i][i+1]*=tmp; a[i+1][i+1]-=a[i][i+1]*a[i+1][i]; x[i+1]-=x[i]*a[i+1][i]; a[i+1][i]=0; } f[id][m]=x[m]; for(int j=m-1;j>0;j--){ x[j]-=a[j][j+1]*x[j+1]; f[id][j]=x[j]; } } int main(){ cin>>n>>m>>xx>>yy; if(m==1){ printf("%d ",(n-xx)*2); return 0; } for(int i=n-1;i>=xx;i--){ a[1][1]=1,a[1][2]=-0.5,x[1]=1.5+f[i+1][1]/2; a[m][m]=1,a[m][m-1]=-0.5,x[m]=1.5+f[i+1][m]/2; for(int j=2;j<m;j++){ a[j][j]=1; a[j][j-1]=-1.0/3; a[j][j+1]=-1.0/3; x[j]=f[i+1][j]/3+4.0/3; } gauss(i); } printf("%.6f ",f[xx][yy]); }