Broken robot CodeForces - 24D (三对角矩阵简化高斯消元+概率dp)

题意:

 

有一个N行M列的矩阵,机器人最初位于第i行和第j列。然后,机器人可以在每一步都转到另一个单元。目的是转到最底部(第N个)行。机器人可以停留在当前单元格处,向左移动,向右移动或移动到当前位置下方的单元格。如果机器人在最左侧的列中,则不能向左移动;如果机器人在最右侧的列中,则不能向右移动。在每一步中,所有可能的移动都是同等可能的。返回到达最底行的预期步数。

 

 

代码+题解:

 

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define mem(a) memset(a,0,sizeof(a))
#define mem__(a) memset(a,-1,sizeof(a))
typedef long long ll;
const int maxn=1e3+10;
const int N=200;
const int INF=0x3f3f3f3f;
const double blo=1.0/3.0;
const double eps=1e-8;
double dp[maxn][maxn],a[maxn][maxn],b[maxn];
int main()
{
    int x,y,n,m;
    scanf("%d%d",&n,&m);
    scanf("%d%d",&x,&y);
    mem(dp);
    if(m==1)
    {
        printf("%.4lf\n",2.0*(n-x));
        return 0;
    }
    /*
    dp[i][1]-1/2dp[i][2]=3/2+1/2dp[i+1][1]
    -1/4dp[i][j-1]+3/4dp[i][j]-1/4dp[i][j+1]=1+1/4dp[i+1][j],1<j<m
    -1/2dp[i][m-1]+dp[i][m]=3/2+1/2dp[i+1][m]
    */
    for(int i=n-1; i>=1; --i)
    {
        /*
        构造一个矩阵
        x1 x2 x3...xn    代表的是未知变量dp[i][j]前面的系数,这个系数放在a数组里面
        由上面三个公式就是分别求dp[i][1]和dp[i][j]和dp[i][m]的公式 
        dp[i][1]需要用到前两个变量dp[i][2]和dp[i+1][1]
        dp[i][j]就需要用到变量dp[i][j-1],dp[i][j+1],dp[i+1][j] 
        dp[i][m]需要用到前两个变量dp[i][m-1]和dp[i+1][m]
        那么它们的系数就会构造一个下面这样的矩阵
        x x 0 0 0    这一行中我们设第一个x为x1,另一个为x2.那么x1=1.0,x2=-1/2 ,b[1]= 3/2+1/2dp[i+1][1],b数组下面有解释 
        x x x 0 0  
        0 x x x 0  
        0 0 x x x  
        0 0 0 x x  
        这个矩阵肯定是一个正方形,因为n个未知数需要n个方程,所以肯定矩阵是一个正方形矩阵
        另外我们还需要一个b数组来保存这n个方程右边的值,这个右边的值是不含未知数,所以是一个已知值 
        
     之后就是高斯消元部分: 我们可以通过方程之间的加减乘除来使这个系数矩阵变成 x x 0 0 0 0 x x 0 0 0 0 x x 0 0 0 0 x x 0 0 0 0 x 然后我们再化简成 x 0 0 0 0 0 x 0 0 0 0 0 x 0 0 0 0 0 x 0 0 0 0 0 x 这个样子的话就变成了一元一次方程,那么一层for循环就可以求出来所有未知量的值
*/ for(int j=2; j<m; ++j) { a[j][j]=-1*3.0/4.0; a[j][j-1]=1.0/4.0; a[j][j+1]=1.0/4.0; b[j]=-1.0-1.0/4.0*dp[i+1][j]; } if(m>=2) { a[m][m] = a[1][1] = -2.0 / 3; a[1][2] = a[m][m - 1] = 1.0 / 3; b[1] = -1 - dp[i + 1][1] / 3.0; b[m] = -1 - dp[i + 1][m] / 3.0; } for(int j = 1; j < m; j++) { if(fabs(a[j+1][j])< eps) continue; double rate = a[j + 1][j] / a[j][j]; for(int k = 0; k < 2; k++) a[j + 1][j + k]-=a[j][j + k]*rate; b[j + 1]-=b[j]*rate; } for(int j = m; j > 1; j--) { if(fabs(a[j - 1][j]) < eps) continue; double rate = a[j - 1][j] / a[j][j]; a[j - 1][j] -= a[j][j] * rate; b[j - 1] -= b[j] * rate; } for(int j=1;j<=m;++j) dp[i][j]=b[j]/a[j][j]; } printf("%.4lf\n",dp[x][y]); return 0; }

 

posted @ 2020-09-12 17:07  kongbursi  阅读(220)  评论(0编辑  收藏  举报