zoukankan      html  css  js  c++  java
  • Random Walk——高斯消元法

    题目

    有一个 $N imes M$ 大小的格子,从(0, 0)出发,每一步朝着上下左右4个格子中可以移动的格子等概率移动。另外有些格子有石头,因此无法移至这些格子。求第一次到达 $(N-1, M-1)$ 格子的期望步数。($2 leq N,Mleq 10$)

    分析

    设 $E(x, y)$ 表示从 (x, y) 出发到终点的期望步数。

    我们先考虑从 $(x, y)$  向上下左右4个方向都可以移动的情况,由于向4个方向的移动的概率是相等的,因此可以建立如下关系:

    $$
    egin{aligned}
    E(x, y) & =  frac{1}{4}(E(x-1, y)+1) + frac{1}{4}(E(x+1,y)+1) + frac{1}{4}(E(x, y-1)+1) + frac{1}{4}(E(x, y+1)+1)\
    &=frac{1}{4}(E(x-1, y) + E(x+1, y) + E(x, y-1) + E(x, y+1)) + 1\
    end{aligned}$$

    如果移动不是等概率,只需要把 1/4 改成相应的数值就可以了。

    如果存在不能移动的方向,我们也可以列出类似的式子。

    为了使方程有唯一解,我们令有石头的格子和无法到达的格子都有 $E(x, y) = 0$。

    把得到的 $N imes M$ 个方程联立,就可以解出期望步数。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 10+5;
    const int maxm = 10+5;
    char grid[maxn][maxm+1];
    int N, M;
    
    bool vis[maxn][maxm];   //can[x][y]为true表示(x, y)能够达到终点
    const int dx[4] = {-1, 0, 1, 0};
    const int dy[4] = {0, 1, 0, -1};
    
    //搜索可以达到终点的点
    void dfs(int x, int y)
    {
        vis[x][y] = true;
        for(int i = 0;i < 4;i++)
        {
            int nx = x + dx[i], ny = y + dy[i];
            if(nx >= 0 && nx <N && ny >= 0 && ny < M && !vis[nx][ny])
                if(grid[nx][ny] != '#')  dfs(nx, ny);
        }
    }
    
    const double eps = 1e-8;
    typedef double Matrix[maxn*maxm][maxn*maxm];
    
    //结果为A[i][n]/A[i][i]
    void gauss_jordan(Matrix A, int n)
    {
    
        int i, j, k, r;
        for(i = 0;i < n;i++)
        {
             //选绝对值一行r并与第i行交换
            r = i;
            for(j = i+1;j < n;j++)
                if(fabs(A[j][i]) > fabs(A[r][i]))  r = j;
            if(fabs(A[r][i]) < eps)  continue;      //放弃这一行,直接处理下一行
            if(r != i)  for(j = 0;j <= n;j++)  swap(A[r][j], A[i][j]);
    
            //与除第i行外的其他行进行消元
            for(k = 0;k < n;k++)  if(k != i)
                for(j = n;j >= i;j--)  A[k][j] -= A[k][i] / A[i][i] * A[i][j];
        }
    }
    
    void debug_print(Matrix A, int n)
    {
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                printf("%f%c", A[i][j], j == n-1 ? '
    ' : ' ');
    }
    
    Matrix A;
    
    int main()
    {
        scanf("%d%d", &N, &M);
        for(int i = 0;i < N;i++)
        {
            char s[15];
            scanf("%s", s);
            for(int j = 0;j < M;j++) grid[i][j] = s[j];
        }
    
        dfs(0, 0);
    
        //构建矩阵
        for(int i = 0;i < N;i++)
            for(int j = 0;j < M;j++)
            {
                if((i == N-1 && j == M-1) || !vis[i][j])  //终点/无法到达的点,令期望步数为0
                {
                    A[i*M + j][i*M + j] = 1;
                    continue;
                }
                int move = 0;
                for(int k = 0;k <4;k++)
                {
                    int nx = i + dx[k], ny = j + dy[k];
                    if(nx >= 0 && nx < N && ny >= 0 && ny < M && grid[nx][ny] == '.')
                    {
                        A[i*M + j][nx*M + ny] = -1;
                        move++;
                    }
                }
                A[i*M + j][i*M + j] = A[i*M + j][N*M] = move;
            }
    
        //debug_print(A, N*M+1);
    
        gauss_jordan(A, N*M);
    
        printf("%.8f
    ", A[0][N*M] / A[0][0]);
        return 0;
    }
  • 相关阅读:
    8月3日云栖精选夜读:LSF-SCNN:一种基于CNN的短文本表达模型及相似度计算的全新优化模型
    linux(centos)下安装PHP的PDO扩展
    Linux中find常见用法示例
    01 编译原理概述
    20145221 《信息安全系统设计基础》第5周学习总结
    20145221 《信息安全系统设计基础》第4周学习总结
    爱春秋之戏说春秋 Writeup
    20145221 《信息安全系统设计基础》第3周学习总结
    20145221 《信息安全系统设计基础》第2周学习总结
    20145221 《信息安全系统设计基础》第1周学习总结
  • 原文地址:https://www.cnblogs.com/lfri/p/11538441.html
Copyright © 2011-2022 走看看