Cod sursa(job #3270932)

Utilizator FunnyStockyMihnea Andreescu FunnyStocky Data 24 ianuarie 2025 21:24:05
Problema Flux maxim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.67 kb
#include <bits/stdc++.h>
using namespace std;

class MaxFlow {
private:
    // Structură pentru o muchie în graful rezidual
    struct Edge {
        int to;    // nodul destinație
        int rev;   // indexul muchiei inverse în lista nodului 'to'
        int cap;   // capacitatea reziduală
    };

    // N = număr de noduri, adj = liste de adiacență
    int N;
    vector<vector<Edge>> adj;

public:
    // Constructor - primește numărul de noduri (N) și redimensionează lista de adiacență
    MaxFlow(int N) : N(N) {
        adj.resize(N + 1);  // indexare de la 1 la N
    }

    // Adăugăm muchia (u -> v) cu capacitatea c și muchia inversă (v -> u) cu capacitatea 0
    void addEdge(int u, int v, int c) {
        Edge a{v, (int)adj[v].size(), c};
        Edge b{u, (int)adj[u].size(), 0};
        adj[u].push_back(a);
        adj[v].push_back(b);
    }

    // Implementarea Edmonds-Karp pentru a calcula fluxul maxim de la s la t
    long long computeFlow(int s, int t) {
        long long maxFlow = 0;

        // Cât timp există drum de ameliorare (BFS)
        while(true){
            vector<int> parent(N + 1, -1);
            vector<int> edgeIndex(N + 1, -1);

            parent[s] = s; // marchează sursa ca vizitată
            queue<int> q;
            q.push(s);

            // BFS pentru a găsi un drum cu capacitate > 0
            while(!q.empty() && parent[t] == -1){
                int u = q.front();
                q.pop();
                for(int i = 0; i < (int)adj[u].size(); i++){
                    const Edge &e = adj[u][i];
                    if(parent[e.to] == -1 && e.cap > 0) {
                        parent[e.to] = u;
                        edgeIndex[e.to] = i;
                        q.push(e.to);
                        if(e.to == t) break; // dacă am ajuns la destinație, ne oprim
                    }
                }
            }

            // Dacă nu am ajuns la t, nu mai există drum de ameliorare
            if(parent[t] == -1)
                break;

            // Determinăm bottleneck-ul (fluxul minim care mai poate fi împins pe acest drum)
            int bottleneck = INT_MAX;
            for(int v = t; v != s; ){
                int u = parent[v];
                int i = edgeIndex[v];
                bottleneck = min(bottleneck, adj[u][i].cap);
                v = u;
            }

            // Actualizăm valorile reziduale (scădem pe muchia directă, creștem pe cea inversă)
            for(int v = t; v != s; ){
                int u = parent[v];
                int i = edgeIndex[v];

                // Scădem capacitatea pe muchia (u -> v)
                adj[u][i].cap -= bottleneck;

                // Creștem capacitatea pe muchia inversă (v -> u)
                int revIndex = adj[u][i].rev;
                adj[v][revIndex].cap += bottleneck;

                v = u;
            }

            maxFlow += bottleneck;
        }

        return maxFlow;
    }
};

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    freopen ("maxflow.in", "r", stdin);
    freopen ("maxflow.out", "w", stdout);

    // Citim datele de intrare
    int N, M;
    cin >> N >> M;

    // Cream obiectul MaxFlow pentru N noduri
    MaxFlow mf(N);

    // Citim muchiile și le adăugăm în structura noastră
    for(int i = 0; i < M; i++){
        int x, y, z;
        cin >> x >> y >> z;
        mf.addEdge(x, y, z);
    }

    // Calculăm fluxul maxim de la nodul 1 (sursa) la nodul N (destinația)
    long long ans = mf.computeFlow(1, N);

    // Afișăm rezultatul
    cout << ans << "\n";

    return 0;
}