c++ - 图表中的 DFS 需要多少时间间隔?
问题描述
问题:
假设您正在对图表进行广度优先搜索。你从一个特定的点开始,然后向外传播。在一个时间间隔内,在给定的条件下,你“感染”了你的邻居。我想知道遍历整个图需要多少时间间隔(即感染所有节点)。
这个问题是一个普遍的问题。但是,我将依靠 LeetCode 示例来提供可重现的内容。
我的做法:
使用队列的基本 bfs。在每次迭代期间,我都会在队列中插入一个间隔元素。如果我找到这个间隔,我知道一个时间间隔已经结束。
队列中的元素q
:
q: a, b, c, timer // a, b and c are infected at first moment in time
q: d, e, timer // above elements infect, d and e.
q: timer // we only have a timer, total traversal took 2 time intervals
为什么我的方法不起作用:
我的方法的基本缺陷是我可能会q
多次推送元素,如果它们会从多个方面受到感染。
带有队列的示例网格q
。q
图中节点的存储索引。 1
健康,2
被感染:
1,1
2,2
q: {0,0}, {0,1}, timer // top 2 elements are in queue. They got infected by bottom 2 elements.
处理第一个元素
2,1
2,2
q: {0,1}, timer, {0,1}
处理第二个元素
2,2
2,2
q: timer, {0,1}, timer
我们将同一个元素推到q
两次,导致时间不正确。(时间 == 2,而不是时间 == 1)。
我该如何解决这个错误?
取自 LeetCode 的示例问题:
我曾经(不)解决LeetCode 问题 994的方法。
class Solution {
struct position {
position(size_t i, size_t j) : i_(i), j_(j), valid_(true) {}
position(bool valid) : i_(0), j_(0), valid_(valid) {}
const size_t i_;
const size_t j_;
const bool valid_;
};
public:
int orangesRotting(vector<vector<int>>& grid) {
if (grid.empty()) return -1;
size_t fresh_orange = 0;
std::queue<position> q;
for (size_t i = 0; i < grid.size(); ++i) {
for (size_t j = 0; j < grid.at(0).size(); ++j) {
int orange = grid.at(i).at(j);
if (orange == 1) {
++fresh_orange;
} else if (orange == 2) {
q.emplace(i, j);
}
}
}
size_t minutes = 0;
q.emplace(false);
while(!q.empty()) {
const position pos = q.front();
q.pop();
if (!pos.valid_ && !q.empty()) {
++minutes;
q.emplace(false);
}
if (!pos.valid_) continue;
// bfs next: top, right, bottom, left
const size_t old_size = q.size();
if (pos.i_ > 0)
if (grid.at(pos.i_ - 1).at(pos.j_) == 1) q.emplace(pos.i_ - 1, pos.j_);
if (pos.j_ < grid.at(0).size() - 1)
if (grid.at(pos.i_).at(pos.j_ + 1) == 1) q.emplace(pos.i_, pos.j_ + 1);
if (pos.i_ < grid.size() - 1)
if (grid.at(pos.i_ + 1).at(pos.j_) == 1) q.emplace(pos.i_ + 1, pos.j_);
if (pos.j_ > 0)
if (grid.at(pos.i_).at(pos.j_ - 1) == 1) q.emplace(pos.i_, pos.j_ - 1);
if (grid.at(pos.i_).at(pos.j_) == 1) {
--fresh_orange;
grid.at(pos.i_).at(pos.j_) = 2;
}
}
return fresh_orange == 0 ? minutes : -1;
}
};
重现我的问题的输入:[[2,2],[1,1],[0,0],[2,0]]
.
解决方案
好的。我有(显而易见的)解决方案:您只需跟踪下一轮谁会被感染。我将-1
其用作“将很快被感染”的标记。
带有队列的示例网格q
。q
图中节点的存储索引。 1
健康,2
被感染:
-1,-1
2, 2
q: {0,0}, {0,1}, timer // top 2 elements are in queue. They got infected by bottom 2 elements.
处理第一个元素
2,-1
2, 2
q: {0,1}, timer, // we do not push back {0,1} since we know it will have symptoms soon
处理第二个元素
2,2
2,2
q: time
对于那些对 LeetCode 解决方案感兴趣的人:
class Solution {
struct position {
position(size_t i, size_t j) : i_(i), j_(j), valid_(true) {}
position(bool valid) : i_(0), j_(0), valid_(valid) {}
const size_t i_;
const size_t j_;
const bool valid_;
};
public:
int orangesRotting(vector<vector<int>>& grid) {
if (grid.empty()) return -1;
size_t fresh_orange = 0;
std::queue<position> q;
for (size_t i = 0; i < grid.size(); ++i) {
for (size_t j = 0; j < grid.at(0).size(); ++j) {
int orange = grid.at(i).at(j);
if (orange == 1) {
++fresh_orange;
} else if (orange == 2) {
q.emplace(i, j);
}
}
}
size_t minutes = 0;
q.emplace(false);
while(!q.empty()) {
const position pos = q.front();
q.pop();
if (!pos.valid_ && !q.empty()) {
++minutes;
q.emplace(false);
}
if (!pos.valid_) continue;
// bfs next: top, right, bottom, left
const size_t old_size = q.size();
if (pos.i_ > 0) {
if (grid.at(pos.i_ - 1).at(pos.j_) == 1) {
grid.at(pos.i_ - 1).at(pos.j_) = -1;
q.emplace(pos.i_ - 1, pos.j_);
}
}
if (pos.j_ < grid.at(0).size() - 1) {
if (grid.at(pos.i_).at(pos.j_ + 1) == 1) {
grid.at(pos.i_).at(pos.j_ + 1) = -1;
q.emplace(pos.i_, pos.j_ + 1);
}
}
if (pos.i_ < grid.size() - 1) {
if (grid.at(pos.i_ + 1).at(pos.j_) == 1) {
grid.at(pos.i_ + 1).at(pos.j_) = -1;
q.emplace(pos.i_ + 1, pos.j_);
}
}
if (pos.j_ > 0) {
if (grid.at(pos.i_).at(pos.j_ - 1) == 1) {
grid.at(pos.i_).at(pos.j_ - 1) = -1;
q.emplace(pos.i_, pos.j_ - 1);
}
}
if (grid.at(pos.i_).at(pos.j_) == 1 || grid.at(pos.i_).at(pos.j_) == -1) {
--fresh_orange;
grid.at(pos.i_).at(pos.j_) = 2;
}
}
return fresh_orange == 0 ? minutes : -1;
}
};
推荐阅读
- jquery - bootstrap-multiselect 如果组没有选项,则默认选择 optgroup
- r - 通过停止函数的特定返回进行重构
- javascript - 无法将字符串变量传递给 JS 日期对象
- python - 如何按两列分组并在新列中分配类别(数字)?
- wikidata-api - Wikidata Api - 子实例和子类的距离树
- python - 抽象类应该返回与预期实现方法相同的类型吗?
- jmeter - Jmeter 没有 GUI 模式运行 .jmx 不包括运行覆盖方法 getDefaultParameters()
- c# - 获取进程关闭原因信息
- nest - 默认 JsonNetSerializer 不使用驼峰式属性名称
- python - Postgres 是否缓存了我们的查询,我们如何绕过它?