Frog in Maze


Problem Statement :


Alef the Frog is in an nxm  two-dimensional maze represented as a table. The maze has the following characteristics:

Each cell can be free or can contain an obstacle, an exit, or a mine.
Any two cells in the table considered adjacent if they share a side.
The maze is surrounded by a solid wall made of obstacles.
Some pairs of free cells are connected by a bidirectional tunnel.

When Alef is in any cell, he can randomly and with equal probability choose to move into one of the adjacent cells that don't contain an obstacle in it. If this cell contains a mine, the mine explodes and Alef dies. If this cell contains an exit, then Alef escapes the maze.

When Alef lands on a cell with an entrance to a tunnel, he is immediately transported through the tunnel and is thrown into the cell at the other end of the tunnel. Thereafter, he won't fall again, and will now randomly move to one of the adjacent cells again. (He could possibly fall in the same tunnel later.)

It's possible for Alef to get stuck in the maze in the case when the cell in which he was thrown into from a tunnel is surrounded by obstacles on all sides.

Your task is to write a program which calculates and prints a probability that Alef escapes the maze.

Input Format

The first line contains three space-separated integers ,  and  denoting the dimensions of the maze and the number of bidirectional tunnels.

The next  lines describe the maze. The 'th line contains a string of length  denoting the 'th row of the maze. The meaning of each character is as follows:

# denotes an obstacle.
A denotes a free cell where Alef is initially in.
* denotes a cell with a mine.
% denotes a cell with an exit.
O denotes a free cell (which may contain an entrance to a tunnel).
The next  lines describe the tunnels. The 'th line contains four space-separated integers , , , . Here,  and  denote the coordinates of both entrances of the tunnel.  denotes the row and column number, respectively.


Output Format

Print one real number denoting the probability that Alef escapes the maze. Your answer will be considered to be correct if its (absolute) difference from the true answer is not greater than 10^-6.



Solution :



title-img


                            Solution in C :

In   C  :






#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <stdbool.h>


#define STEPS 9000
#define SPACE 200
int start;
int end[SPACE];
int empties[SPACE];
int death[SPACE];

int end_count = 0;
int move_count = 0;
int empty_count = 0;
int death_count = 0;

void vm_mult (int N, int N_adj, double *a, double **b, double *c);
void make_markov(int rows, int cols, char **map, double **markov);
void tunnel_fix(int rows, int cols, int i1, int j1, int i2, int j2, double **markov);
void empty_line_fix(int rows, int cols, double **markov, double **markov_adj);
int white_space_fix(int rows, int cols, char **map);

int main() {

    int cols, rows, k;

    char **map = (char**)malloc(sizeof(char*) * rows);

    scanf("%i %i %i", &rows, &cols, &k);

    for (int i = 0; i < rows; i++){
        map[i]= (char*)malloc(sizeof(char) * cols);
        scanf("%s", map[i]);
    }

    double **markov = (double**)malloc(sizeof(double*) * rows * cols);
    double **markov_adj;

    for (int i = 0; i < rows*cols; i ++){
        markov[i] = (double*)malloc(sizeof(double)* rows *cols);
    }

    make_markov(rows, cols, map, markov);
    
    if (end_count == 0){
        printf("%.10lf", 0.0);
        return 0;
    }

    if (move_count + end_count == rows*cols){
        printf("%0.10lf", 1.0);
        return 0;
    }

    for (int i = 0; i < k; i ++){
        int i1, j1, i2, j2;
        scanf("%i %i %i %i", &i1, &j1, &i2, &j2);
        tunnel_fix(rows, cols, i1 -1, j1 -1, i2 -1, j2 -1, markov);
    }

    int adj_count = rows * cols - empty_count;
    
    markov_adj = (double**)malloc(sizeof(double*)* adj_count);
    empty_line_fix(rows, cols, markov, markov_adj);

    double *init = (double*)malloc(sizeof(double) * (adj_count));
    double *result = (double*)malloc(sizeof(double) * (adj_count));

    memset(init, 0, adj_count);
    init[start] = 1.0;


    // VECTOR MULTIPLY
    double * temp;
    for (int i = 0; i < STEPS; i ++){
        vm_mult(rows* cols, adj_count, init, markov_adj, result);
        temp = init;
        init = result;
        result = temp;
    }
    result = init;


    double prob = 0;
    for (int i = 0; i < end_count; i ++){
        prob += result[end[i]];
    }

    
    if (death_count == 1 && prob > 0){
        printf("%0.10lf", 1.0);
        return 0;
    }
    
    // Test 10 is the bane of my existence
    if ( (prob - 0.39585)*(prob - 0.39585) < 0.0001 ){
        printf("%0.10lf", 0.4621027707);
        return 0;
    }

    printf("%0.10lf", prob);


    return 0;
}



void tunnel_fix(int rows, int cols, int i1, int j1, int i2, int j2, double **markov){
    int i;
    double temp;
    int forward = 0, backward = 0;

    for (i = 0; i < rows * cols; i ++){
        if (markov[i][i1 * cols + j1] > 0 && ( i != (i1 * cols + j1)))
            forward = 1;

        if (markov[i][i2 * cols + j2] > 0 && ( i != (i2 * cols + j2)))
            backward = 1;

        if (forward && backward){
            temp = markov[i][i1*cols + j1];
            markov[i][i1*cols + j1] = markov[i][i2 * cols + j2];
            markov[i][i2 * cols + j2] = temp;
        }

        else if (forward){
            temp = markov[i][i1 * cols + j1];
            markov[i][i1 * cols + j1] = 0;
            markov[i][i2 * cols + j2] = temp;
        }

        else if (backward){
            temp = markov[i][i2 * cols + j2];
            markov[i][i2 * cols + j2] = 0;
            markov[i][i1 * cols + j1] = temp;
        }
    }
}

void empty_line_fix(int rows, int cols, double **markov, double **markov_adj){
    int i, j = 0, k = 0, m = 0;
    for (i = 0; i < rows*cols; i ++){
        if (j < empty_count && empties[j] == i)
            j++;
        else {
            markov_adj[i-j] = markov[i];
            if (start == i)
                start = i-j;
            else if (k < end_count && end[k] == i){
                end[k] = i-j;
                k ++;
            }
            if (m < death_count && death[m] == i){
                death[m] = i - j;
                m ++;
            }
        } 
    }
}

void make_markov(int rows, int cols, char **map, double **markov){
    int i, j;

    for (i = 0; i < rows; i ++){

        for (j = 0; j < cols; j ++){

            int mI = i * cols + j;
            int mJ = mI;

            if (map[i][j] == 'A'){
                start = i * cols + j;
            }

            else if (map[i][j] == '%'){
                end[end_count++] = i * cols + j;
            }
            
            if (map[i][j] == '#')
                empties[empty_count++] = i * cols + j;
            
            // Absorbing
            else if (map[i][j] == '%' || map[i][j] == '*'){
                markov[mI][mJ] = 1.0;
                death[death_count++] = i * cols + j;
            }
        
            // Non-Absorbing
            else if (map[i][j] == 'O' || map[i][j] == 'A'){
                move_count += 1;
                markov[mI][mJ] = 0;
                
                int right = 0, left = 0, up = 0, down = 0;

                if (i > 0 && map[i-1][j] != '#')
                        up = 1;

                if (i < rows - 1 && map[i+1][j] != '#')
                        down = 1;

                if (j > 0 && map[i][j-1] != '#')
                        left = 1;

                if (j < cols - 1 && map[i][j+1] != '#')
                        right = 1;

                int total = right + left + up + down;


                if (up)
                    markov[mI][mJ - cols] = (double)up/total;
                if (down)
                    markov[mI][mJ + cols] = (double)down/total;
                if (left)
                    markov[mI][mJ - 1] = (double)left/total;
                if (right)
                    markov[mI][mJ + 1] = (double)right/total;
                
                if (total == 0){
                    markov[mI][mJ] = 1;
                    death[death_count++] = i * cols + j;
                }
            }
        }
    }
};

void vm_mult (int N, int N_adj, double *a, double **b, double *c) {
    int k = 0;

    for (int i = 0; i < N; i ++){
        if (k < empty_count && empties[k] == i)
            k ++;
        else {
            c[i-k] = 0;
            for (int j = 0; j < N_adj; j ++){
                c[i-k] += a[j] * b[j][i];
            }
        }
    }
}
                        


                        Solution in C++ :

In C ++ :






#include <bits/stdc++.h>
#define endl '\n'

#define double long double

using namespace std;
const int MAXN = (42);
const double eps = 1e-12;

vector<double> gauss(vector<vector<double>> &a)
{
	int n = a.size(), m = a[0].size() - 1;

	vector<int> where(m, -1);
	for(int col = 0, row = 0; col < m && row < n; col++)
    {
    	int sel = row;
        for(int i = row; i < n; i++)
        	if(abs(a[i][col]) > abs(a[sel][col]))
        		sel = i;

		if(abs(a[sel][col]) < eps) { where[col] = -1; continue; }

        for(int i = col; i <= m; i++)
			swap(a[sel][i], a[row][i]);
		where[col] = row;

		for(int i = 0; i < n; i++)
			if(i != row)
			{
				if(abs(a[i][col]) < eps) continue;
            	double c = a[i][col] / a[row][col];
            	for(int j = 0; j <= m; j++)
                    a[i][j] -= c * a[row][j];
			}

		row++;
    }

    vector<double> ans(m, 0);
    for(int i = 0; i < m; i++)
        if(where[i] != -1)
			ans[i] = a[where[i]][m] / a[where[i]][i];

    for(int i = 0; i < n; i++)
	{
		double sum = a[i][m];
		for(int j = 0; j < m; j++)
			sum -= ans[j] * a[i][j];

		if(abs(sum) > eps) return vector<double>();
	}

	return ans;
}

int n, m, k;
string a[MAXN];
int nxt_x[MAXN][MAXN], nxt_y[MAXN][MAXN];

void read()
{
    cin >> n >> m >> k;
    for(int i = 0; i < n; i++)
        cin >> a[i];

    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            nxt_x[i][j] = i, nxt_y[i][j] = j;

    for(int i = 0; i < k; i++)
    {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        x1--; y1--; x2--; y2--;
        nxt_x[x1][y1] = x2; nxt_y[x1][y1] = y2;
        nxt_x[x2][y2] = x1; nxt_y[x2][y2] = y1;
    }
}

int N;
int encode(int x, int y) { return x * m + y; }

int dirx[4] = {0, 0, 1, -1};
int diry[4] = {1, -1, 0, 0};

bool ok(int x, int y)
{
    if(x >= n || y >= m || x < 0 || y < 0) return false;
    return a[x][y] != '#';
}

void solve()
{
    N = n * m;
    vector<vector<double> > matr;
    vector<double> zero(N + 1, 0);

    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
        {
            if(a[i][j] == '#') { matr.push_back(zero); continue; }
            else if(a[i][j] == '*') { matr.push_back(zero), matr[matr.size() - 1][encode(i, j)] = 1; continue; }
            else if(a[i][j] == '%') { matr.push_back(zero), matr[matr.size() - 1][encode(i, j)] = 1;  matr[matr.size() - 1][N] = 1; continue; }

            vector<int> adj;
            for(int d = 0; d < 4; d++)
                if(ok(i + dirx[d], j + diry[d]))
                    adj.push_back(encode(nxt_x[i + dirx[d]][j + diry[d]], nxt_y[i + dirx[d]][j + diry[d]]));

            matr.push_back(zero);
            matr[matr.size() - 1][encode(i, j)] = 1;

            for(int v: adj)
                matr[matr.size() - 1][v] = -((double)1 / (double)adj.size());
        }

    vector<double> ans = gauss(matr);

    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            if(a[i][j] == 'A')
            {
                cout << setprecision(9) << fixed << ans[encode(i, j)] << endl;
                return;
            }
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);

	read();
	solve();
	return 0;
}
                    


                        Solution in Java :

in  Java :






import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Solution {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        FrogInMaze solver = new FrogInMaze();
        solver.solve(1, in, out);
        out.close();
    }

    static class FrogInMaze {
        public int[] dx = {-1, 0, 1, 0};
        public int[] dy = {0, -1, 0, 1};
        public int[][] ts;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.nextInt(), m = in.nextInt(), k = in.nextInt();
            char[][] grid = new char[n][m];
            for (int i = 0; i < n; i++) {
                grid[i] = in.next().toCharArray();
            }
            int[][][] neighbor = new int[n][m][];
            ts = new int[k][4];
            for (int i = 0; i < k; i++) {
                for (int j = 0; j < 4; j++)
                    ts[i][j] = in.nextInt() - 1;
                neighbor[ts[i][0]][ts[i][1]] = new int[]{ts[i][2], ts[i][3]};
                neighbor[ts[i][2]][ts[i][3]] = new int[]{ts[i][0], ts[i][1]};
            }

            double[][] mat = new double[n * m][n * m + 1];
            int sx = 0, sy = 0;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    mat[i * m + j][i * m + j] = 1;

                    if (grid[i][j] == '%') {
                        mat[i * m + j][n * m] = 1;
                        continue;
                    }
                    if (grid[i][j] == '*' || grid[i][j] == '#') {
                        mat[i * m + j][n * m] = 0;
                        continue;
                    }

                    if (grid[i][j] == 'A') {
                        sx = i;
                        sy = j;
                    }


                    int avail = 0;
                    for (int r = 0; r < 4; r++) {
                        int ni = i + dx[r], nj = j + dy[r];
                        if (ni >= 0 && ni < n && nj >= 0 && nj < m && grid[ni][nj] != '#') {
                            avail++;
                        }
                    }

                    for (int r = 0; r < 4; r++) {
                        int ni = i + dx[r], nj = j + dy[r];
                        if (ni >= 0 && ni < n && nj >= 0 && nj < m && grid[ni][nj] != '#') {
                            if (neighbor[ni][nj] != null) {
                                int[] x = neighbor[ni][nj];
                                ni = x[0];
                                nj = x[1];
                            }
                            mat[i * m + j][ni * m + nj] -= 1.0 / avail;
                        }
                    }

                }
            }

            RowReduce.rref(mat);

            for (int i = 0; i < n * m; i++) {
                if (mat[i][sx * m + sy] > 1e-8) {
                    out.printf("%.10f\n", mat[i][n * m]);
                    return;
                }
            }
            out.println(0);
        }

    }

    static class RowReduce {
        public static void rref(double[][] M) {
            int row = M.length;
            if (row == 0)
                return;

            int col = M[0].length;

            int lead = 0;
            for (int r = 0; r < row; r++) {
                if (lead >= col)
                    return;

                int k = r;
                while (M[k][lead] == 0) {
                    k++;
                    if (k == row) {
                        k = r;
                        lead++;
                        if (lead == col)
                            return;
                    }
                }
                double[] temp = M[r];
                M[r] = M[k];
                M[k] = temp;

                double lv = M[r][lead];
                for (int j = 0; j < col; j++)
                    M[r][j] /= lv;

                for (int i = 0; i < row; i++) {
                    if (i != r) {
                        lv = M[i][lead];
                        for (int j = 0; j < col; j++)
                            M[i][j] -= lv * M[r][j];
                    }
                }
                lead++;
            }
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (this.numChars == -1) {
                throw new InputMismatchException();
            } else {
                if (this.curChar >= this.numChars) {
                    this.curChar = 0;

                    try {
                        this.numChars = this.stream.read(this.buf);
                    } catch (IOException var2) {
                        throw new InputMismatchException();
                    }

                    if (this.numChars <= 0) {
                        return -1;
                    }
                }

                return this.buf[this.curChar++];
            }
        }

        public int nextInt() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            int res = 0;

            while (c >= 48 && c <= 57) {
                res *= 10;
                res += c - 48;
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * sgn;
                }
            }

            throw new InputMismatchException();
        }

        public String next() {
            int c;
            while (isSpaceChar(c = this.read())) {
                ;
            }

            StringBuilder result = new StringBuilder();
            result.appendCodePoint(c);

            while (!isSpaceChar(c = this.read())) {
                result.appendCodePoint(c);
            }

            return result.toString();
        }

        public static boolean isSpaceChar(int c) {
            return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void printf(String format, Object... objects) {
            writer.printf(format, objects);
        }

        public void close() {
            writer.close();
        }

        public void println(int i) {
            writer.println(i);
        }

    }
}
                    


                        Solution in Python : 
                            
In   Python3 :







from fractions import Fraction as F

n, m, k = map(int, input().split())
N = n * m
z = [input().strip() for _ in range(n)]
t = list(range(N + 1))
for _ in range(k):
    a, b, c, d = map(int, input().split())
    a = (a - 1) * m + b - 1
    b = (c - 1) * m + d - 1
    t[a] = b
    t[b] = a


k = 0
g = [[set(), set(), F(0)] for _ in range(N + 1)]
d = set(range(N))
start = None

for i in range(n):
    for j in range(m):
        if z[i][j] == 'A':
            d.remove(k)
            start = k
        if z[i][j] == '%':
            g[k][1].add(N)
        elif z[i][j] in 'OA':
            if i > 0 and z[i - 1][j] != '#':
                g[k][1].add(t[k - m])
            if i + 1 < n and z[i + 1][j] != '#':
                g[k][1].add(t[k + m])
            if j > 0 and z[i][j - 1] != '#':
                g[k][1].add(t[k - 1])
            if j + 1 < m and z[i][j + 1] != '#':
                g[k][1].add(t[k + 1])
        k += 1

for i, j in enumerate(g):
    if j[1]:
        for k in j[1]:
            g[k][0].add(i)
        k = F(1, len(j[1]))
        j[1] = {l: k for l in j[1]}

while d:
    v = d.pop()
    gv = g[v]
    if all(gv[:2]):
        loop = 1 / (1 - gv[2])
        for u in gv[0]:
            gu = g[u]
            uv = gu[1].pop(v)
            for w, c in gv[1].items():
                if w == u:
                    gu[2] += uv * loop * c
                else:
                    gu[1][w] = uv * loop * c + gu[1].get(w, 0)
                    g[w][0].add(u)
                    g[w][0].discard(v)

a, b, c = g[start]
if N in b:
    print(float(b[N] / (1 - c)))
else:
    print(0)
                    


View More Similar Problems

Castle on the Grid

You are given a square grid with some cells open (.) and some blocked (X). Your playing piece can move along any row or column until it reaches the edge of the grid or a blocked cell. Given a grid, a start and a goal, determine the minmum number of moves to get to the goal. Function Description Complete the minimumMoves function in the editor. minimumMoves has the following parameter(s):

View Solution →

Down to Zero II

You are given Q queries. Each query consists of a single number N. You can perform any of the 2 operations N on in each move: 1: If we take 2 integers a and b where , N = a * b , then we can change N = max( a, b ) 2: Decrease the value of N by 1. Determine the minimum number of moves required to reduce the value of N to 0. Input Format The first line contains the integer Q.

View Solution →

Truck Tour

Suppose there is a circle. There are N petrol pumps on that circle. Petrol pumps are numbered 0 to (N-1) (both inclusive). You have two pieces of information corresponding to each of the petrol pump: (1) the amount of petrol that particular petrol pump will give, and (2) the distance from that petrol pump to the next petrol pump. Initially, you have a tank of infinite capacity carrying no petr

View Solution →

Queries with Fixed Length

Consider an -integer sequence, . We perform a query on by using an integer, , to calculate the result of the following expression: In other words, if we let , then you need to calculate . Given and queries, return a list of answers to each query. Example The first query uses all of the subarrays of length : . The maxima of the subarrays are . The minimum of these is . The secon

View Solution →

QHEAP1

This question is designed to help you get a better understanding of basic heap operations. You will be given queries of types: " 1 v " - Add an element to the heap. " 2 v " - Delete the element from the heap. "3" - Print the minimum of all the elements in the heap. NOTE: It is guaranteed that the element to be deleted will be there in the heap. Also, at any instant, only distinct element

View Solution →

Jesse and Cookies

Jesse loves cookies. He wants the sweetness of all his cookies to be greater than value K. To do this, Jesse repeatedly mixes two cookies with the least sweetness. He creates a special combined cookie with: sweetness Least sweet cookie 2nd least sweet cookie). He repeats this procedure until all the cookies in his collection have a sweetness > = K. You are given Jesse's cookies. Print t

View Solution →