package com.interview.graph;
import java.util.LinkedList;
import java.util.Queue;
enum Cell{
SPACE,
BLOCK,
GUARD
}
class Point{
int x;
int y;
Point(int x, int y){
this.x = x;
this.y = y;
}
}
/**
* @Date 07/05/2015
* @author Tushar Roy
*
* Given a 2 D floor plan with empty space, block and multiple exits. Find distance of every empty space
* from nearest exits in case of fire emergency.
*
* Idea is to start from every exit position and do BFS search in all 4 directions and maintain the distance of every
* space from exit. If another exit in future iterator is closer than already calculated exit then update
* the distance.
*
* Space complexity is O(n*m)
* Time complexity is O(number of exit * m * n);
*
*/
public class ShortestDistanceFromExit {
public int[][] findShortest(Cell input[][]){
int distance[][] = new int[input.length][input[0].length];
for(int i=0; i < input.length; i++){
for(int j=0; j < input[0].length; j++){
distance[i][j] = Integer.MAX_VALUE;
}
}
for(int i=0; i < input.length; i++){
for(int j =0; j < input[i].length; j++){
//for every exit location do a BFS starting with this exit as the origin
if(input[i][j] == Cell.GUARD){
distance[i][j] = 0;
setDistance(input, i, j, distance);
}
}
}
return distance;
}
private void setDistance(Cell input[][], int x, int y, int distance[][]){
boolean visited[][] = new boolean[input.length][input[0].length];
Queue<Point> q = new LinkedList<>();
q.offer(new Point(x,y));
//Do a BFS at keep updating distance.
while(!q.isEmpty()){
Point p = q.poll();
setDistanceUtil(q, input, p, getNeighbor(input, p.x+1, p.y), distance, visited);
setDistanceUtil(q, input, p, getNeighbor(input, p.x, p.y+1), distance, visited);
setDistanceUtil(q, input, p, getNeighbor(input, p.x-1, p.y), distance, visited);
setDistanceUtil(q, input, p, getNeighbor(input, p.x, p.y-1), distance, visited);
}
}
private void setDistanceUtil(Queue<Point> q, Cell input[][], Point p, Point newPoint, int distance[][], boolean visited[][]){
if(newPoint != null && !visited[newPoint.x][newPoint.y]){
if(input[newPoint.x][newPoint.y] != Cell.GUARD && input[newPoint.x][newPoint.y] != Cell.BLOCK){
distance[newPoint.x][newPoint.y] = Math.min(distance[newPoint.x][newPoint.y], 1 + distance[p.x][p.y]);
visited[newPoint.x][newPoint.y] = true;
q.offer(newPoint);
}
}
}
private Point getNeighbor(Cell input[][], int x, int y){
if(x < 0 || x >= input.length || y < 0 || y >= input[0].length ) {
return null;
}
return new Point(x,y);
}
public static void main(String args[]){
ShortestDistanceFromExit sdg = new ShortestDistanceFromExit();
Cell input[][] = {{Cell.SPACE, Cell.SPACE, Cell.BLOCK, Cell.BLOCK},
{Cell.SPACE, Cell.SPACE, Cell.GUARD, Cell.SPACE},
{Cell.SPACE, Cell.SPACE, Cell.BLOCK, Cell.SPACE},
{Cell.SPACE, Cell.GUARD, Cell.BLOCK, Cell.SPACE}
};
int result[][] = sdg.findShortest(input);
for(int i=0; i < result.length; i++) {
for(int j=0; j < result[0].length; j++){
System.out.print(result[i][j] + " ");
}
System.out.println();
}
}
}