vis的目的其实并不是已经访问过哪些节点,而是记录【[在当前步骤] 或 [之前的步骤]】中已经访问过的状态。因为之前已经访问过了这些状态,而之前那些访问用的步骤更少,因此之后就没必要再次访问这些状态了。
当用bfs用于记录到达某个状态的步骤时,则若某个节点 【曾经访问过】或【通步骤的其他状态已经将这个节点加入队列】,则不用再将这个节点加入队列:
while (!sourceq.empty()) {
level_count = sourceq.size();
while ((level_count--) > 0) {
auto p = sourceq.front();
sourceq.pop();
for (int i=0; i<4; i++) {
int subx = p.first + dx[i];
int suby = p.second + dy[i];
if (subx >= 0 && suby >= 0 && subx < m && suby < n) {
if (A[subx][suby] == 1) {
return step;
} else if (A[subx][suby] == 0 && vis2[subx][suby] == 0){
sourceq.push({subx,suby});
vis2[subx][suby]=1;
}
}
}
}
或者:
while (!sourceq.empty()) {
level_count = sourceq.size();
while ((level_count--) > 0) {
auto p = sourceq.front();
sourceq.pop();
if (vis2[p.first][p.second] == 1) {
continue;
}
vis2[p.first][p.second] = 1;
for (int i=0; i<4; i++) {
int subx = p.first + dx[i];
int suby = p.second + dy[i];
if (subx >= 0 && suby >= 0 && subx < m && suby < n) {
if (A[subx][suby] == 1) {
return step;
} else if (A[subx][suby] == 0){
sourceq.push({subx,suby});
}
}
}
}
step++;
}
但不能这样:
while (!sourceq.empty()) {
level_count = sourceq.size();
while ((level_count--) > 0) {
auto p = sourceq.front();
sourceq.pop();
// 1:
if (vis2[p.first][p.second] == 1) {
continue;
}
vis2[p.first][p.second] = 1;
for (int i=0; i<4; i++) {
int subx = p.first + dx[i];
int suby = p.second + dy[i];
if (subx >= 0 && suby >= 0 && subx < m && suby < n) {
if (A[subx][suby] == 1) {
return step;
} else if (A[subx][suby] == 0 && vis2[subx][suby] == 0){
// 2:
sourceq.push({subx,suby});
vis2[subx][suby]=1;
}
}
}
}
这样做的话,因为2处已经将vis2[subx][suby]设置为1,则访问这个节点时,因为1处代码的存在,会直接跳过访问这个节点。
另外,若有多个起始状态的bfs出现了tle,可能的原因是:队列中的起始状态有重复的,不妨试试没有重复时可不可以度过难关。做leetcode::934::最短的桥时就因为这种原因tle了