Codeforces 24D - Broken Robot
题意
有一个机器人,最开始在 \((x,y)\) 点。它下一步可能向左边,右边,下面走,或者停在原地(如果是靠边的位置那么只有三种选择),每种选择是等概率的。
问走到第 \(n\) 行的期望步数。
\(n,m\le 1000\)
分析
每一行显然可以由下一行和当前行的相邻位置表示,列出方程组。
这个方程组中第 \(i\) 行只有 \(i-1,i,i+1,m+1\) 列是有数的,所以可以 \(O(n)\) 求解,即每次只对下一行消元。
可以这样消元的原因是,每一行的数加到下一行去不会把其他位置也变为 0 。若会的话就要考虑交换行,非常麻烦,也是因为没有发现这个想了很久。
总复杂度为 \(O(n^2)\) 。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;
double F[2][maxn],*f=F[0],*g=F[1],a[maxn][maxn];
int n,m,sx,sy;
inline void print(double x) {printf("%.10lf\n",x);}
void make() {
for (int i=1;i<=m;++i) {
a[i][i]=3-(i==1 || i==m);
a[i][i-1]=a[i][i+1]=-1;
a[i][m+1]=g[i]+4-(i==1 || i==m);
}
}
void elim() {
for (int i=1;i<m;++i) {
double w=a[i+1][i]/a[i][i];
for (int j=i;j<i+3 && j<=m;++j) a[i+1][j]-=a[i][j]*w;
a[i+1][m+1]-=a[i][m+1]*w;
}
for (int i=m;i>1;--i) {
double w=a[i-1][i]/a[i][i];
for (int j=i;j<i+3 && j<=m;++j) a[i-1][j]-=a[i][j]*w;
a[i-1][m+1]-=a[i][m+1]*w;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
scanf("%d%d%d%d",&n,&m,&sx,&sy);
if (m==1) print((n-sx)*2),exit(0);
for (int i=n-1;i>=sx;--i) {
swap(f,g);
make();
elim();
for (int j=1;j<=m;++j) f[j]=a[j][m+1]/a[j][j];
}
print(f[sy]);
return 0;
}