您的位置:首页 > 其它

《挑战》例题4.1 Random Walk

2015-10-20 14:50 246 查看
1.题目描述:有一个n*m的网格,从(0,0)出发,每一步可以朝着上下左右4个方向等概率地移动,另外一些格子中有石头,因此无法移动到这些格子,求第一次到达(n-1,m-1)格子的期望步数。可以保证至少存在一条从(0,0)到(n-1,m-1)的路径。

范围:2<=n,m<=10

样例:

Input

3 10

.#...#...#

.#.#.#.#.#

...#...#..

Output

361.00000000

2.解题思路:不妨设E(x,y)表示从(x,y)出发,到终点的期望步数,那么根据期望的线性性质和全期望公式,可以得到如下方程。

E(x,y)=0.25*E(x-1,y)+0.25*E(x+1,y)+0.25*E(x,y-1)+0.25*E(x,y+1)+1;

上述方程通过移项可以变成下式:

4*E(x,y)-E(x-1,y)-E(x+1,y)-E(x,y-1)-E(x,y+1)=4;

E(n-1,m-1)=0;

为了使得方程具有唯一解,我们令所有含有石头的格子和无法到达终点的格子都有E(x,y)=0。把这些方程联立,就可以求出最终的期望步数了。注意:建立矩阵的时候,要把二维先化成一维:(x,y)->x*m+y ,这样,便得到了一个n*m阶的系数矩阵。

3.代码:

#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<complex>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;

#define rep(i,n) for(int i=0;i<(n);i++)
#define me(s) memset(s,0,sizeof(s))
#define pb push_back
#define lid (id<<1)
#define rid (id<<1|1)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;

const int N=100+10;
const double eps=1e-8;
typedef double Matrix

;
Matrix A;

void gauss(int n)
{
int r;
for(int i=0;i<n;i++)
{
r=i;
for(int j=i+1;j<n;j++)
if(fabs(A[j][i])>fabs(A[r][i]))r=j;
if(r!=i)for(int j=0;j<=n;j++)swap(A[r][j],A[i][j]);
for(int j=i+1;j<=n;j++)
A[i][j]/=A[i][i];
A[i][i]=1.0;
for(int k=0;k<n;k++)
{
if(fabs(A[k][i])<eps||k==i)continue;
double f=A[k][i];
for(int j=0;j<=n;j++)
A[k][j]-=f*A[i][j];
}
}
}

char g

;
int vis

;
int n,m;
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
bool inside(int x,int y){return x>=0&&x<n&&y>=0&&y<m;}

void dfs(int x,int y)
{
vis[x][y]=1;
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(inside(nx,ny)&&g[nx][ny]!='#'&&!vis[nx][ny])
{
dfs(nx,ny);
}
}
}

void solve()
{
me(A);
me(vis);
dfs(n-1,m-1);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(i==n-1&&j==m-1||!vis[i][j])
{
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(inside(nx,ny)&&g[nx][ny]=='.')
{
A[i*m+j][nx*m+ny]=-1;
move++;
}
}
A[i*m+j][n*m]=A[i*m+j][i*m+j]=move;
}
gauss(n*m);
}

int main()
{
while(~scanf("%d%d",&n,&m))
{
rep(i,n)scanf("%s",g[i]);
solve();
printf("%.10lf\n",A[0][n*m]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息