Cod sursa(job #3357160)

Utilizator parus_majorParus Major parus_major Data 6 iunie 2026 18:08:55
Problema Critice Scor 90
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.57 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

struct Edge {
    int to;
    int cap;
    int flow;
    int rev_idx;
    int id; // ID-ul original al muchiei din fisier
};

int N, M;
vector<vector<Edge>> adj;
vector<pair<int, int>> original_edges; // Retine capetele pentru verificare finala
vector<int> parent_edge;
vector<int> parent_node;
vector<bool> vis_S, vis_T;

// BFS pentru gasirea drumului de imbunatatire in Edmonds-Karp
bool bfs(int source, int sink) {
    fill(parent_node.begin(), parent_node.end(), -1);
    queue<int> q;
    q.push(source);
    parent_node[source] = source;

    while (!q.empty()) {
        int u = q.front();
        q.pop();

        if (u == sink) return true;

        for (int i = 0; i < adj[u].size(); ++i) {
            Edge& e = adj[u][i];
            if (parent_node[e.to] == -1 && e.cap - e.flow > 0) {
                parent_node[e.to] = u;
                parent_edge[e.to] = i;
                q.push(e.to);
            }
        }
    }
    return false;
}

// Algoritmul Edmonds-Karp pentru flux maxim
void max_flow(int source, int sink) {
    parent_edge.assign(N + 1, -1);
    parent_node.assign(N + 1, -1);

    while (bfs(source, sink)) {
        int push_flow = 2e9;

        // Gasim capacitatea reziduala minima pe drum
        for (int v = sink; v != source; v = parent_node[v]) {
            int u = parent_node[v];
            int idx = parent_edge[v];
            push_flow = min(push_flow, adj[u][idx].cap - adj[u][idx].flow);
        }

        // Actualizam fluxul in retea
        for (int v = sink; v != source; v = parent_node[v]) {
            int u = parent_node[v];
            int idx = parent_edge[v];
            int rev_idx = adj[u][idx].rev_idx;

            adj[u][idx].flow += push_flow;
            adj[v][rev_idx].flow -= push_flow;
        }
    }
}

// BFS din sursa pentru a gasi componentele accesibile in graful rezidual
void bfs_S(int source) {
    vis_S.assign(N + 1, false);
    queue<int> q;
    q.push(source);
    vis_S[source] = true;

    while (!q.empty()) {
        int u = q.front();
        q.pop();

        for (const auto& e : adj[u]) {
            if (!vis_S[e.to] && e.cap - e.flow > 0) {
                vis_S[e.to] = true;
                q.push(e.to);
            }
        }
    }
}

// BFS invers din destinatie pentru a gasi nodurile care pot ajunge la sink
void bfs_T(int sink) {
    vis_T.assign(N + 1, false);
    queue<int> q;
    q.push(sink);
    vis_T[sink] = true;

    while (!q.empty()) {
        int u = q.front();
        q.pop();

        for (const auto& e : adj[u]) {
            // Mergem invers: daca muchia de la e.to la u are capacitate reziduala
            // Inseamna ca e.to poate trimite flux catre u. 
            // In codul nostru, e.to -> u are fluxul e.flow inversat in arcul pereche.
            int rev_idx = e.rev_idx;
            if (!vis_T[e.to] && adj[e.to][rev_idx].cap - adj[e.to][rev_idx].flow > 0) {
                vis_T[e.to] = true;
                q.push(e.to);
            }
        }
    }
}

int main() {
    ifstream fin("critice.in");
    ofstream fout("critice.out");

    if (!fin) return 0;

    fin >> N >> M;
    adj.resize(N + 1);
    original_edges.resize(M + 1);

    for (int i = 1; i <= M; ++i) {
        int u, v, c;
        fin >> u >> v >> c;
        original_edges[i] = { u, v };

        // Adaugam arcul u -> v
        Edge a = { v, c, 0, (int)adj[v].size(), i };
        // Adaugam arcul v -> u (deoarece graful este neorientat)
        Edge b = { u, c, 0, (int)adj[u].size(), i };

        adj[u].push_back(a);
        adj[v].push_back(b);
    }

    // Pasul 1: Calculam fluxul maxim de la 1 la N
    max_flow(1, N);

    // Pasul 2: Identificam multimile S si T in graful rezidual
    bfs_S(1);
    bfs_T(N);

    // Pasul 3: Gasim muchiile critice
    vector<int> critical_edges;
    for (int i = 1; i <= M; ++i) {
        int u = original_edges[i].first;
        int v = original_edges[i].second;

        // O muchie este critica daca un capat este in S, celalalt in T
        // si este complet saturata pe acea directie.
        if ((vis_S[u] && vis_T[v]) || (vis_S[v] && vis_T[u])) {
            critical_edges.push_back(i);
        }
    }

    // Sortam indicii descriptorilor (sunt deja sortati deoarece i creste de la 1 la M)
    fout << critical_edges.size() << "\n";
    for (int id : critical_edges) {
        fout << id << "\n";
    }

    return 0;
}