317 Shortest Distance from All Buildings
namespace std {
template <> struct hash<std::pair<int, int>> {
inline size_t operator()(const std::pair<int, int> &v) const {
std::hash<int> int_hasher;
return int_hasher(v.first) ^ int_hasher(v.second);
}
};
}
bool isSteppable(const vector<vector<int>> &visited, const int row, const int col) {
return (row >= 0 && row < visited.size()
&& col >= 0 && col < visited[row].size()
&& visited[row][col] == 0
);
}
bool isHouse(const vector<vector<int>> &visited, const int row, const int col) {
return (row >= 0 && row < visited.size()
&& col >= 0 && col < visited[row].size()
&& visited[row][col] == 1);
}
unordered_set<pair<int, int>> findTargets(vector<vector<int>> &grid, int target) {
unordered_set<pair<int, int>> stuff;
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid.at(i).size(); j++) {
if (grid[i][j] == target) {
stuff.insert({ i,j });
}
}
}
return stuff;
}
// key:
// 0 - empty field
// 1 - house
// 2 - obsticle
// 3 - visited field
// 4 - visited house
tuple<bool, unordered_set<pair<int,int>>, vector<vector<int>>> BFSgrid(const int row, const int col, vector<vector<int>> BFS_grid,
vector<vector<int>> visited, unordered_set<pair<int,int>> houses,
const vector<function<pair<int, int>(int, int)>> &directions) {
queue<pair<int, int>> q;
q.push({ row, col });
visited[row][col] = 4;
houses.erase({ row, col });
while (!q.empty()) {
pair<int,int> front = q.front();
q.pop();
for (auto functor : directions) {
pair<int, int> next = functor(front.first, front.second);
if (isSteppable(visited, next.first, next.second)) {
BFS_grid[next.first][next.second] = BFS_grid[front.first][front.second] + 1;
visited[next.first][next.second] = 3;
q.push({next.first, next.second});
}
else if (isHouse(visited, next.first, next.second)) {
visited[next.first][next.second] = 4; // dont want to erase something empty next time
houses.erase({ next.first, next.second });
}
}
}
// result whether bfs was valid or not, the blocks that were blocked off, and the bfs grid to accumulate into tensor
return { houses.empty(), findTargets(visited, 0), BFS_grid };
}
int sumAndFindMin(const vector<vector<vector<int>>> &tensor, const vector<vector<int>> &visited) {
int minSum = INT_MAX;
const size_t rows = visited.size();
const size_t cols = visited.at(0).size();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (visited[i][j] == 0) {
int tempSum = 0;
for (int k = 0; k < tensor.size(); k++) {
tempSum += tensor[k][i][j];
}
minSum = min(minSum, tempSum);
}
}
}
return (minSum == INT_MAX) ? -1 : minSum;
}
int shortestDistance(vector<vector<int>>& grid) {
auto up = [&](int row, int col) {
return make_pair(--row, col);
};
auto down = [&](int row, int col) {
return make_pair(++row, col);
};
auto left = [&](int row, int col) {
return make_pair(row, --col);
};
auto right = [&](int row, int col) {
return make_pair(row, ++col);
};
vector<function<pair<int, int>(int, int)>> cardinalDirections = { up, down, left, right };
unordered_set<pair<int, int>> houses = findTargets(grid, 1);
vector<vector<int>> integral_BFS_grid(grid.size(), vector<int>(grid.at(0).size()));
vector<vector<vector<int>>> tensor;
tensor.reserve(houses.size());
for (pair<int,int> p : houses) {
tuple<bool, unordered_set<pair<int,int>>, vector<vector<int>>> result = BFSgrid(p.first, p.second,
integral_BFS_grid, grid, houses, cardinalDirections);
if (!get<0>(result)) {
return -1;
}
// mark unexplored fields to be invalid (fill in the gaps as an obsticle)
for (auto i : get<1>(result))
grid[i.first][i.second] = 2;
tensor.push_back(get<2>(result));
}
return sumAndFindMin(tensor, grid);
}Last updated