#include <vector>
#include <iostream>
#include <climits>
#include <queue>
using namespace std;
/*
You want to build a house on an empty land which reaches all buildings in the shortest amount of distance. You can only move up, down, left and right. You are given a 2D grid of values 0, 1 or 2, where:
Each 0 marks an empty land which you can pass by freely.
Each 1 marks a building which you cannot pass through.
Each 2 marks an obstacle which you cannot pass through.
For example, given three buildings at (0,0), (0,4), (2,2), and an obstacle at (0,2):
1 - 0 - 2 - 0 - 1
| | | | |
0 - 0 - 0 - 0 - 0
| | | | |
0 - 0 - 1 - 0 - 0
The point (1,2) is an ideal empty land to build a house, as the total travel distance of 3+3+1=7 is minimal. So return 7.
Note:
There will be at least one building. If it is not possible to build such house according to the above rules, return -1.
*/
/*
Analyze:
we start from "1" value and write down the steps to reach each node. If the node is reachable, we remember the reachable status as "-1". Thus, we need to maintain two tables. One is to remember the steps, the other to remember the reachable status.
*/
// canAchieve value mark the achievable nodes layerly. If the node is not achievable, it will always be '0'.
void BFS(vector< vector<int> >& grid, int i, int j, vector< vector<int> >& steps, vector< vector<int> >& canReach, int& canAchieve) {
int m = grid.size();
int n = grid[0].size();
struct posAndStep {
int x;
int y;
posAndStep(int k, int h) : x(k), y(h) {};
};
vector< vector<int> > tmpStep(m, vector<int>(n, 0));
vector< vector<int> > dir {
{0, 1},
{0, -1},
{1, 0},
{-1, 0}};
queue<posAndStep> nodes;
posAndStep start(i, j);
nodes.push(start);
while(!nodes.empty()) {
auto curr = nodes.front();
nodes.pop();
for(auto direction : dir) {
int next_x = curr.x + direction[0];
int next_y = curr.y + direction[1];
if(next_x < m && next_x >= 0 && next_y < n && next_y >= 0 && (canReach[next_x][next_y] == canAchieve)) {
--canReach[next_x][next_y];
posAndStep next_node(next_x, next_y);
tmpStep[next_x][next_y] = tmpStep[curr.x][curr.y] + 1;
steps[next_x][next_y] += tmpStep[next_x][next_y];
nodes.push(next_node);
}
}
}
--canAchieve;
}
int shortestDistance(vector< vector<int> >& grid) {
if(grid.size() == 0 || grid[0].size() == 0) return 0;
int m = grid.size();
int n = grid[0].size();
vector< vector<int> > steps(m, vector<int>(n, 0));
vector< vector<int> > canReach = grid;
// BFS to cacualte the step and remember the status.
int canAchieve = 0;
for(int i = 0; i < m; ++i) {
for(int j = 0; j < n; ++j) {
if(grid[i][j] == 1) {
BFS(grid, i, j, steps, canReach, canAchieve);
}
}
}
int minDistant = INT_MAX;
for(int i = 0; i < m; ++i) {
for(int j = 0; j < n; ++j) {
if(steps[i][j] && canReach[i][j]) {
minDistant = min(minDistant, steps[i][j]);
}
}
}
return minDistant;
}
int main(void) {
vector< vector<int> > matrix{
{1, 0, 2, 0, 1},
{0, 0, 0, 0, 0},
{0, 0, 1, 0, 0}};
cout << shortestDistance(matrix) << endl;
}