← Все вопросы

Почему мой BFS на сетке даёт TLE, хотя алгоритм правильный?

Задан 22 месяца назад1.5к просмотров2 ответа
8

BFS на сетке 1000×1000 правильно находит путь, но получаю TLE/MLE на максимальных тестах. Алгоритм же O(V+E)... Что я делаю не так и как ускорить?

2 ответа

12
✓ Принятый ответ — помог автору

Алгоритм верный, но константа убивает. Типичные причины на больших сетках:

  1. map/set для visited вместо массива. map<pair<int,int>, int> добавляет log и огромную константу. Используйте плоский vector<int> dist(R*C, -1) с индексом r*C + c.
  2. Хранение очереди из строк/пар с лишними копиями. Кодируйте клетку одним int = r*C + c.
  3. Создание соседей через временный vector/tuple в каждой итерации. Лучше массивы dr[] = {0,0,1,-1}, dc[] = {1,-1,0,0}.
  4. std::endl в выводе (flush каждый раз) — заменяйте на '\n'.
int dr[] = {0,0,1,-1}, dc[] = {1,-1,0,0};
vector<int> dist(R*C, -1);
queue<int> q;
dist[s] = 0; q.push(s);
while (!q.empty()) {
    int cur = q.front(); q.pop();
    int r = cur / C, c = cur % C;
    for (int k = 0; k < 4; k++) {
        int nr = r+dr[k], nc = c+dc[k];
        if (nr<0||nr>=R||nc<0||nc>=C) continue;
        int nx = nr*C + nc;
        if (dist[nx] == -1 && grid[nr][nc] != '#') {
            dist[nx] = dist[cur] + 1; q.push(nx);
        }
    }
}

Сложность остаётся O(R·C), но с маленькой константой — проходит.

5

Ещё про MLE: на 10^6 клеток queue<pair<int,int>> или queue<tuple<...>> ест много памяти из-за оверхеда std::deque-блоков. Кодирование клетки в один int и быстрый ввод (scanf/cin с ios::sync_with_stdio(false)) часто и есть разница между TLE и AC. Профилируйте: чаще всего виноват не сам BFS, а структуры-обёртки вокруг него.

Ваш ответ

Войдите, чтобы ответить на вопрос.