Broken robot 题解
题目链接
分析
记 \(f[i][j]\) 为从 \(i\) 行 \(j\) 列到最后一行的期望,则
\( f[i][j]= \begin{cases} \frac{1}{3}(f[i][j]+f[i][j+1]+f[i+1][j])+1 &i=1\\ \frac{1}{4}(f[i][j]+f[i][j-1]+f[i,j+1]+f[i+1][j])+1 &1<i<m\\ \frac{1}{3}(f[i][j]+f[i][j-1]+f[i+1][j])+1 &i=m \end{cases} \)
我们发现第 \(i\) 层只与第 \(i+1\) 层有关
可以在每一层中通过高斯消元求解
举个例子
当 \(m=5\) 时,可以列出如下方程组
\( \begin{bmatrix} &2 &-1 &0 &0 &0 &3f[i+1][1]+1\\ &-1 &3 &-1 &0 &0 &4f[i+1][2]+1\\ &0 &-1 &3 &-1 &0 &4f[i+1][3]+1\\ &0 &0 &-1 &3 &-1 &4f[i+1][4]+1\\ &0 &0 &0 &-1 &2 &3f[i+1][5]+1 \end{bmatrix} \)
发现系数十分有规律,扫上下两边即可求解(具体见代码)
这样一次消元的复杂度为 \(O(M)\)
总的复杂度为 \(O(MN)\)
注意:
高斯-约旦消元的时间复杂度是不正确的
当计算第 \(i\) 行时,第 \(i+1\) 列的所有 \(0\) 都会减一个数
导致计算 \(i+1\) 行时需要将所有行更新一次
代码
#include<bits/stdc++.h>
using namespace std;
#define db double
const int N=1e3+100;
int n,m,x,y;
db f[N],gs[N][N];//f[i]为当前层的第i列
void wk(){
for(int i=1;i<=m;i++){
if(i==1||i==m) f[i]+=3.0;
else f[i]+=4.0;
}
for(int i=1;i<=m;i++){//Gauss消元
db c=gs[i+1][i]/gs[i][i];
f[i+1]-=f[i]*c;
gs[i+1][i]-=gs[i][i]*c;
gs[i+1][i+1]-=gs[i][i+1]*c;
}
for(int i=m;i;i--){
if(i!=m) f[i]+=f[i+1];
f[i]/=gs[i][i];
}
}
int main(){
scanf("%d %d %d %d", &n, &m, &x, &y);
for(int i=1;i<=m;i++) f[i]=0.0;
if(m==1){
for(int i=n-1;i>=x;i--) f[1]=f[1]+2.0;
printf("%.4lf", f[1]);
return 0;
}
for(int i=n-1;i>=x;i--){//只需计算到x即可
memset(gs,0,sizeof(gs));
for(int i=1;i<=m;i++){
if(i==1||i==m) gs[i][i]=2.0;
else gs[i][i]=3.0;
if(i!=1) gs[i][i-1]=-1.0;
if(i!=m) gs[i][i+1]=-1.0;
}
wk();
}
printf("%.4lf", f[y]);
return 0;
}