SRM 356 950pt : EscapeTheJail
keyword
連立一次方程式 期待値 C++
問題概要
N*M(N,M<15)のボードがあり、スタート地点、ゴール地点(複数)、壁が指定されている。到達可能なマスを等確率で選んで移動するとき、ゴールにたどり着くまでのターン数の期待値を求める問題。
解法
蟻本に載ってるランダムウォークの問題とほとんど同じ。ゴールが複数あるという違いくらいしかない。
#include <vector> #include <string> #include <cmath> using namespace std; int dy[] = {1,-1,0,0}; int dx[] = {0,0,1,-1}; vector<string> jail; int N, M, S; const double EPS = 1e-10; double A[15*15][15*15]; double b[15*15]; struct EscapeTheJail { double findExit(vector <string> _jail) { jail = _jail; N = jail.size(); M = jail[0].size(); S = N*M; int sx=-1, sy=-1; for(int i=0; i<N; i++)for(int j=0; j<M; j++){ if(jail[i][j] == '@'){ sy = i; sx = j; jail[i][j] = '.'; } if(jail[i][j] == '$'){ jail[i][j] = '.'; } } dfs(sy, sx); bool found = false; for(int i=0; i<N; i++)for(int j=0; j<M; j++){ if(_jail[i][j] == '$' && jail[i][j] == '*'){ found = true; } } if(!found) return -1.0; for(int i=0; i<N; i++)for(int j=0; j<M; j++){ if(jail[i][j] != '*') jail[i][j] = '#'; } for(int i=0; i<N; i++)for(int j=0; j<M; j++){ if(_jail[i][j] == '$'){ A[i*M + j][i*M + j] = 1.0; b[i*M + j] = 0.0; continue; } int cnt = 0; b[i*M + j] = 1.0; A[i*M + j][i*M + j] = 1.0; for(int k=0; k<4; k++){ int ny = i + dy[k], nx = j + dx[k]; if(0 <= ny && ny < N && 0 <= nx && nx < M && jail[ny][nx] == '*'){ cnt++; } } for(int k=0; k<4; k++){ int ny = i + dy[k], nx = j + dx[k]; if(0 <= ny && ny < N && 0 <= nx && nx < M && jail[ny][nx] == '*'){ A[i*M + j][ny*M + nx] = -1.0/cnt; } } } gauss_jordan(); return b[sy*M + sx]; } void dfs(int y, int x){ jail[y][x] = '*'; for(int k=0; k<4; k++){ int ny = y + dy[k], nx = x + dx[k]; if(0 <= ny && ny < N && 0 <= nx && nx < M && jail[ny][nx] == '.'){ dfs(ny,nx); } } } void gauss_jordan(){ for(int i=0; i<S; i++){ int pivot = i; for(int j=i; j<S; j++){ if(fabs(A[j][i]) > fabs(A[pivot][i])) pivot = j; } for(int j=0; j<S; j++){ swap(A[i][j], A[pivot][j]); } swap(b[i], b[pivot]); if(fabs(A[i][i]) < EPS){ for(int j=0; j<S; j++){ b[j] = -1; } return ; } for(int j=i+1; j<S; j++) A[i][j] /= A[i][i]; b[i] /= A[i][i]; for(int j=0; j<S; j++){ if(i != j){ for(int k=i+1; k<S; k++){ A[j][k] -= A[j][i]*A[i][k]; } b[j] -= A[j][i] * b[i]; } } } } };