Grafosc++BFSgrafoscamino más corto

BFS en Grafos

Búsqueda en amplitud aplicada a grafos para caminos más cortos y exploraciones nivel a nivel

OOI Oaxaca9 de febrero de 20264 min read

BFS en grafos: repaso rápido

Ya vimos BFS en la sección de búsquedas. Aquí nos enfocamos en sus aplicaciones específicas en grafos.

Camino más corto (sin pesos)

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

const int MAXN = 100005;
vector<int> adj[MAXN];
int dist[MAXN];
int padre[MAXN];
bool vis[MAXN];

void bfs(int inicio, int n) {
    fill(dist, dist + n + 1, -1);
    fill(padre, padre + n + 1, -1);

    queue<int> q;
    q.push(inicio);
    dist[inicio] = 0;

    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int v : adj[u]) {
            if (dist[v] == -1) {
                dist[v] = dist[u] + 1;
                padre[v] = u;
                q.push(v);
            }
        }
    }
}

vector<int> reconstruirCamino(int destino) {
    vector<int> camino;
    for (int v = destino; v != -1; v = padre[v]) {
        camino.push_back(v);
    }
    reverse(camino.begin(), camino.end());
    return camino;
}

int main() {
    int n, m;
    cin >> n >> m;

    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    int origen, destino;
    cin >> origen >> destino;

    bfs(origen, n);

    if (dist[destino] == -1) {
        cout << "No hay camino" << endl;
    } else {
        cout << "Distancia: " << dist[destino] << endl;
        cout << "Camino: ";
        for (int v : reconstruirCamino(destino)) {
            cout << v << " ";
        }
        cout << endl;
    }

    return 0;
}

BFS 0-1

Cuando las aristas tienen peso 0 o 1, puedes usar una variante de BFS con un deque en lugar de una cola normal:

void bfs01(int inicio, int n) {
    fill(dist, dist + n + 1, INT_MAX);
    deque<int> dq;

    dist[inicio] = 0;
    dq.push_front(inicio);

    while (!dq.empty()) {
        int u = dq.front(); dq.pop_front();

        for (auto [v, w] : adj[u]) {  // adj almacena {vecino, peso}
            if (dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
                if (w == 0) {
                    dq.push_front(v);  // Peso 0: alta prioridad
                } else {
                    dq.push_back(v);   // Peso 1: baja prioridad
                }
            }
        }
    }
}

Complejidad: O(V+E)O(V + E), igual que BFS normal.

Verificar si un grafo es bipartito

Un grafo es bipartito si puedes colorear sus nodos con 2 colores sin que dos nodos adyacentes tengan el mismo color.

int color[MAXN];  // -1 = sin color

bool esBipartito(int inicio) {
    queue<int> q;
    q.push(inicio);
    color[inicio] = 0;

    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int v : adj[u]) {
            if (color[v] == -1) {
                color[v] = 1 - color[u];
                q.push(v);
            } else if (color[v] == color[u]) {
                return false;  // Conflicto
            }
        }
    }
    return true;
}

BFS multi-fuente

Calcular la distancia mínima desde cualquier fuente:

void bfsMultiFuente(vector<int> &fuentes, int n) {
    fill(dist, dist + n + 1, -1);
    queue<int> q;

    for (int f : fuentes) {
        dist[f] = 0;
        q.push(f);
    }

    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int v : adj[u]) {
            if (dist[v] == -1) {
                dist[v] = dist[u] + 1;
                q.push(v);
            }
        }
    }
}

Ejercicio de práctica

Dado un grafo no dirigido con N nodos y M aristas, encuentra la distancia más corta entre los nodos S y T. Si no hay camino, imprime -1.

Ver solución
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

vector<int> adj[100005];
int dist[100005];

int main() {
    int n, m, s, t;
    cin >> n >> m >> s >> t;

    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    fill(dist, dist + n + 1, -1);
    queue<int> q;
    q.push(s);
    dist[s] = 0;

    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int v : adj[u]) {
            if (dist[v] == -1) {
                dist[v] = dist[u] + 1;
                q.push(v);
            }
        }
    }

    cout << dist[t] << endl;
    return 0;
}