codeforces 24d Broken robot 期望+高斯消元

题目传送门

题意:在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",(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\n",f[xx][yy]);
}

 

posted @ 2019-09-04 15:34  光芒万丈小太阳  阅读(196)  评论(0编辑  收藏  举报