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;
}
posted @ 2017-10-20 19:59 permui 阅读(...) 评论(...) 编辑 收藏