Emparelhamento de Pilotos usando Fluxo em Rede

Em uma esquadrilha, existem n pilotos, dos quais m são pilotos principais (co-pilotos não são especificados, mas a numeração implica que pilotos principais têm números menores). Cada aeronave requer exatamente um piloto principal e um co-piloto. No entanto, certos pares de um piloto principal e um co-piloto são incompatíveis devido a restrições operacionais, tornando-os incapazes de voar juntos. O objetivo é determinar o número máximo de pares viáveis para maximizar as aeronaves em operação.

O problema pode ser modelado como um grafo bipartido, onde os pilotos principais e co-pilotos representam partições distintas. As arestas entre elas indicam compatibilidade. A busca por um emparelhamento máximo equivale a encontrar o fluxo máximo em uma rede, com uma fonte conectada a todos os pilotos princiapis e um sumidouro a todos os co-pilotos, todas as arestas tendo capacidade 1.

Formato de Entrada

A primeira linha contém dois inteiros n e m, onde n é o número total de pilotos e m é o número de pilotos principais. As subsequentes linhas contêm pares a b, indicando que o piloto principal a e o co-piloto b podem voar juntos. Os pilotos principais têm números entre 1 e m, e os co-pilotos entre m+1 e n. Restrições: 2 ≤ n ≤ 100.

Formato de Saída

Uma única linha com o número máximo de aeronaves que podem ser emparelhadas.

Exemplo de Entrada

10 5
1 7
2 6
2 10
3 7
4 8
5 9

Exemplo de Saída

4

Implemantação em C++ usando o Algoritmo de Dinic

O código a seguir resolve o problema calculando o fluxo máximo. A rede é construída com uma fonte e um sumidouro, e arestas de capacidade unitária. O algoritmo de Dinic é empregado para eficiência.

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

const int MAX_NOS = 110;
const int INFINITO = 1e9;

struct Aresta {
    int destino, capacidade, proximo;
};

vector<Aresta> arestas;
int cabecalho[MAX_NOS];
int nivel[MAX_NOS];
int total_arestas;

void adicionarAresta(int origem, int destino, int capacidade) {
    arestas.push_back({destino, capacidade, cabecalho[origem]});
    cabecalho[origem] = total_arestas++;
    arestas.push_back({origem, 0, cabecalho[destino]});
    cabecalho[destino] = total_arestas++;
}

bool bfs(int fonte, int sumidouro) {
    memset(nivel, -1, sizeof(nivel));
    queue<int> fila;
    fila.push(fonte);
    nivel[fonte] = 0;
    while (!fila.empty()) {
        int no = fila.front();
        fila.pop();
        for (int idx = cabecalho[no]; idx != -1; idx = arestas[idx].proximo) {
            int vizinho = arestas[idx].destino;
            if (nivel[vizinho] == -1 && arestas[idx].capacidade > 0) {
                nivel[vizinho] = nivel[no] + 1;
                fila.push(vizinho);
            }
        }
    }
    return nivel[sumidouro] != -1;
}

int dfs(int no, int fluxo, int sumidouro) {
    if (no == sumidouro) return fluxo;
    for (int idx = cabecalho[no]; idx != -1; idx = arestas[idx].proximo) {
        int vizinho = arestas[idx].destino;
        if (nivel[vizinho] == nivel[no] + 1 && arestas[idx].capacidade > 0) {
            int fluxoEnviado = dfs(vizinho, min(fluxo, arestas[idx].capacidade), sumidouro);
            if (fluxoEnviado > 0) {
                arestas[idx].capacidade -= fluxoEnviado;
                arestas[idx ^ 1].capacidade += fluxoEnviado;
                return fluxoEnviado;
            }
        }
    }
    return 0;
}

int dinic(int fonte, int sumidouro) {
    int fluxoMaximo = 0;
    while (bfs(fonte, sumidouro)) {
        int fluxo;
        while ((fluxo = dfs(fonte, INFINITO, sumidouro)) > 0) {
            fluxoMaximo += fluxo;
        }
    }
    return fluxoMaximo;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    memset(cabecalho, -1, sizeof(cabecalho));
    total_arestas = 0;

    int n, m;
    cin >> n >> m;

    int fonte = 0, sumidouro = n + 1;
    for (int i = 1; i <= m; ++i) {
        adicionarAresta(fonte, i, 1);
    }
    for (int i = m + 1; i <= n; ++i) {
        adicionarAresta(i, sumidouro, 1);
    }

    int pilotoPrincipal, coPiloto;
    while (cin >> pilotoPrincipal >> coPiloto) {
        adicionarAresta(pilotoPrincipal, coPiloto, 1);
    }

    cout << dinic(fonte, sumidouro) << endl;
    return 0;
}

Tags: fluxo-em-rede dinic-algoritmo C++ grafos-bipartidos emparelhamento-máximo

Publicado em 6-20 01:25