坏掉的机器人(后效性处理&&高斯消元)

给定一张 N*M 的棋盘,有一个机器人处于(x,y)位置。

这个机器人可以进行很多轮行动,每次等概率地随机选择停在原地、向左移动一格、向右移动一格或向下移动一格。

当然机器人不能移出棋盘。

求机器人从起点走到最后一行的任意一个位置上,所需行动次数的数学期望值。

输入格式

第一行包含两个整数 N 和 M。

第二行包含两个整数 x 和 y,表示机器人的初始位置。

设定棋盘左上角为(1,1),右下角为(N,M)。

输出格式

输出一个实数,表示数学期望,结果保留四位小数。

数据范围

1≤N,M≤1000

输入样例:

10 14 
5 14

输出样例:

18.0038

 解题过程:

用f[i][j]表示位于(i,j)坐标时,所需行动次数的数学期望值

具体过程如下图所示:

坏掉的机器人(后效性处理&&高斯消元)_第1张图片

注:

j在[2,m-1]时

f[i][j]=1/4((f[i][j]+1)+(f[i][j-1]+1)+(f[i][j+1]+1)+(f[i+1][j]+1))

将括号中的四个1加起来乘1/4就等价于把1提到括号外=1/4(f[i][j]+f[i][j-1]+f[i][j+1]+f[i+1][j])+1

其他范围的式子同理可得

然后用高斯消元将每个f[i][j]求出,最终f[x][y]即为答案

完整代码:

#include 
#include 
#include 

using namespace std;

const int maxn=1010;

double f[maxn][maxn],a[maxn][maxn];
int n,m,x,y;

void gauss()
{
    ////每次用首非零元a[i][i]消掉其下面的那一列,化成上三角矩阵
    for(int i=1;i<=m;i++){
        double k=a[i+1][i]/a[i][i];//计算消的时候乘的系数,(a[i][i]是用来消的数作为分母,a[i+1][i]是当前要消掉的数作为分子)
        int d[3]={i,i+1,m+1};//每行只有这三个位置的数不为0
        for(int j=0;j<3;j++){
            a[i+1][d[j]]-=a[i][d[j]]*k;//被削行减去k倍的用来消的行:(如用a消掉b 即:b-a*(b/a)=0)
        }
        a[i+1][i]=0;//当前首非零元对应的下面那个数就被消掉了
    }
    //从最后一行往前依次用当前行系数矩阵中最后一个元素消掉系数矩阵中上一行的最后一个元素,把矩阵最终化成对角阵
    for(int i=m;i;i--){
        double k=a[i-1][i]/a[i][i];
        a[i-1][m+1]-=a[i][m+1]*k;//因为是行运算,所以该行每个数都要进行相同的运算
        a[i-1][i]=0;//当前第i行系数矩阵的最后一个数的上面那个数就被消掉了
    }
}

int main()
{
    cin>>n>>m>>x>>y;
    if(m==1) printf("%.4f\n",2.0*(n-x));
    else{
        for(int i=n-1;i>=x;i--){
            //构造增广矩阵:
            //1、构造首尾两行
            a[1][1]=2.0/3,a[1][2]=-1.0/3,a[1][m+1]=f[i+1][1]/3+1;
            a[m][m-1]=-1.0/3,a[m][m]=2.0/3,a[m][m+1]=f[i+1][m]/3+1;
            //2、构造中间[2,m-1]行:
            for(int j=2;j<=m-1;j++){
                a[j][j-1]=-1.0/4,a[j][j]=3.0/4,a[j][j+1]=-1.0/4;
                a[j][m+1]=f[i+1][j]/4+1;
            }
            gauss();//对增广矩阵进行高斯消元
            for(int j=1;j<=m;j++) f[i][j]=a[j][m+1]/a[j][j];
        }
        printf("%.4f\n",f[x][y]);
    }
    return 0;
}

 

你可能感兴趣的:(dp,数论)