题目
思路
方法一:有限步数的BFS
对于空间中一点,n个障碍点在最理想的情况下最多可包围n(n-1)/2个点,因此可得到思路:
1.对起点进行广度优先搜索,在n(n-1)/2点内找到了终点,则返回true;若遍历的点小于n(n-1)/2,则返回false;若在n(n-1)/2点内未找到终点,进行下一步;
2.对终点进行广度优先搜索,在n(n-1)/2点内找到了起点,则返回true;若遍历的点小于n(n-1)/2,则返回false;若在n(n-1)/2点内未找到起点,返回true。
方法二:离散化+BFS
对于所有点进行离散化处理,若行/列剧烈大于等于2,调整为2;若距离为1或者0,不变,即可得到规模较小的图,然后在其上进行遍历。
算法实现
方法一:
class Solution {
private:
// 在包围圈中
static constexpr int BLOCKED = -1;
// 不在包围圈中
static constexpr int VALID = 0;
// 无论在不在包围圈中,但在n(n-1)/2步搜索中经过了target
static constexpr int FOUND = 1;
static constexpr int dirs[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
static constexpr int BOUNDARY = 1000000;
public:
bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
if (blocked.size() < 2)
return true;
auto hash_fn = [fn = hash<long long>()](const pair<int, int>& o)->size_t {
auto& x = o;
return fn((long long)x.first << 20 | x.second);
};
unordered_set<pair<int, int>, decltype(hash_fn)> hash_blocked(0, hash_fn);
for (const auto& pos : blocked)
hash_blocked.emplace(pos[0], pos[1]);
auto check = [&](vector<int>& start, vector<int>& finish)-> int {
int sx = start[0], sy = start[1];
int fx = finish[0], fy = finish[1];
int countdown = blocked.size() * (blocked.size() - 1) / 2;
queue<pair<int, int>> q;
q.emplace(sx, sy);
unordered_set<pair<int, int>, decltype(hash_fn)> visited(0, hash_fn);
visited.emplace(sx, sy);
while (!q.empty() && countdown > 0) {
auto x = q.front();
q.pop();
for (int d = 0; d < 4; ++d) {
int nx = x.first + dirs[d][0], ny = x.second + dirs[d][1];
if (nx >= 0 && nx < BOUNDARY && ny >= 0 && ny < BOUNDARY &&
!hash_blocked.count({ nx, ny }) && !visited.count({ nx, ny })) {
if (nx == fx && ny == fy)
return FOUND;
--countdown;
q.emplace(nx, ny);
visited.emplace(nx, ny);
}
}
}
if (countdown > 0)
return BLOCKED;
return VALID;
};
int result = check(source, target);
if (result == FOUND)
return true;
else if (result == BLOCKED)
return false;
else {
result = check(target, source);
if (result == BLOCKED)
return false;
return true;
}
}
};
方法二:
class Solution {
private:
static constexpr int BOUNDARY = 1000000;
static constexpr int dirs[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
public:
bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
if (blocked.size() < 2) {
return true;
}
vector<int> rows, columns;
for (const auto& pos : blocked) {
rows.push_back(pos[0]);
columns.push_back(pos[1]);
}
rows.push_back(source[0]);
rows.push_back(target[0]);
columns.push_back(source[1]);
columns.push_back(target[1]);
sort(rows.begin(), rows.end());
sort(columns.begin(), columns.end());
rows.erase(unique(rows.begin(), rows.end()), rows.end());
columns.erase(unique(columns.begin(), columns.end()), columns.end());
unordered_map<int, int> r_mapping, c_mapping;
int r_id = (rows[0] == 0 ? 0 : 1);
r_mapping[rows[0]] = r_id;
for (int i = 1; i < rows.size(); ++i) {
r_id += (rows[i] == rows[i - 1] + 1 ? 1 : 2);
r_mapping[rows[i]] = r_id;
}
if (rows.back() != BOUNDARY - 1)
++r_id;
int c_id = (columns[0] == 0 ? 0 : 1);
c_mapping[columns[0]] = c_id;
for (int i = 1; i < columns.size(); ++i) {
c_id += (columns[i] == columns[i - 1] + 1 ? 1 : 2);
c_mapping[columns[i]] = c_id;
}
if (columns.back() != BOUNDARY - 1) {
++c_id;
}
vector<vector<int>> grid(r_id + 1, vector<int>(c_id + 1));
for (const auto& pos : blocked) {
int x = pos[0], y = pos[1];
grid[r_mapping[x]][c_mapping[y]] = 1;
}
int sx = r_mapping[source[0]], sy = c_mapping[source[1]];
int tx = r_mapping[target[0]], ty = c_mapping[target[1]];
queue<pair<int, int>> q;
q.emplace(sx, sy);
grid[sx][sy] = 1;
while (!q.empty()) {
auto x = q.front();
q.pop();
for (int d = 0; d < 4; ++d) {
int nx = x.first + dirs[d][0], ny = x.second + dirs[d][1];
if (nx >= 0 && nx <= r_id && ny >= 0 && ny <= c_id && grid[nx][ny] != 1) {
if (nx == tx && ny == ty) {
return true;
}
q.emplace(nx, ny);
grid[nx][ny] = 1;
}
}
}
return false;
}
};