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  阅读(245)  评论(0编辑  收藏  举报