Cod sursa(job #2958845)

Utilizator popashtefan10Popa Stefan popashtefan10 Data 28 decembrie 2022 16:41:12
Problema Flux maxim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.69 kb
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>

using namespace std;

const int NMAX = 1000;
const int MMAX = 5000;
const int INF = 110000000;

class Flow {
  struct Edge {
    int from, to;
    int cf;

    Edge(int from = 0, int to = 0, int cf = 0) : from(from), to(to), cf(cf) {}
  };

  int n, m;
  int source, destination;
  // adjList[i] = indicii muchiilor care pornesc din nodul i
  vector<vector<int>> adjList;
  vector<Edge> edges;
  // dad[i] = indicele muchiei parinte din arborele BFS
  vector<int> dad;

  // adauga flux in drumul de ameliorare care se termina in nodul dat ca parametru si intoarce valoarea fluxului adaugat
  int addFlow(int node) {
    int canAdd = -1; // fluxul maxim pe care il pot adauga pe drumul de ameliorare curent
    int crt = node;
    while(crt != source) {
      if(canAdd == -1 || edges[dad[crt]].cf < canAdd)
        canAdd = edges[dad[crt]].cf;
      crt = edges[dad[crt]].from;
    }

    // parcurg din nou drumul de ameliorare ca sa adaug noul flux
    crt = node;
    while(crt != source) {
      edges[dad[crt]].cf -= canAdd;
      edges[dad[crt] ^ 1].cf += canAdd;
      crt = edges[dad[crt]].from;
    }

    return canAdd;
  }

  // creeaza arborele BFS prin vectorul de tati si intoarce daca a gasit macar un drum de ameliorare sau nu
  bool bfs() {
    bool reachedDestination = false; // daca am ajuns la destinatie printr-un drum de ameliorare
    queue<int> q;
    q.push(source);
    for(int i = 1; i <= n; i++)
      dad[i] = -1;

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

      for(int edgeIdx: adjList[node]) {
        int ngh = edges[edgeIdx].to;
        // caut muchii in care mai pot adauga flux si care ajung in noduri nevizitate
        if(ngh == source || dad[ngh] != -1 || edges[edgeIdx].cf == 0)
          continue;
        // daca am ajuns la destinatie nu memorez nodul din care am ajuns pentru ca pot avea mai multe drumuri
        if(ngh == destination) {
          reachedDestination = true;
          continue;
        }

        dad[ngh] = edgeIdx;
        q.push(ngh);
      }
    }

    return reachedDestination;
  }

public:
  void init(int n, int source = 1, int destination = -1) {
    this->n = n;
    this->source = source;
    this->destination = destination == -1 ? n : destination;
    adjList.resize(n + 1);
    dad.resize(n + 1);
  }

  // adauga muchia (from, to) in retea; indicele muchiei va fi pe o pozitie para, iar muchia inversa va fi pe urmatoarea pozitie
  void addEdge(int from, int to, int capacity) {
    edges.push_back(Edge(from, to, capacity));
    adjList[from].push_back(edges.size() - 1);
    // adaug si muchia inversa de capacitate 0
    edges.push_back(Edge(to, from, 0));
    adjList[to].push_back(edges.size() - 1);
  }

  // intoarce fluxul maxim din retea
  int maxFlow() {
    int maxFlow = 0;

    // cat timp exista drumuri de ameliorare mai putem adauga flux
    while(bfs())
      for(int edgeIdx: adjList[destination]) {
        int node = edges[edgeIdx].to;

        // conectam pe rand nodul destinatie la toate nodurile din care se poate ajunge in acesta si care sunt capatul unui drum de ameliorare
        if((node == source || dad[node] != -1) && edges[edgeIdx ^ 1].cf > 0) {
          dad[destination] = edgeIdx ^ 1;
          maxFlow += addFlow(destination);
        }
      }

    return maxFlow;
  }
};

void read(Flow &flow) {
  int n, m;
  
  scanf("%d %d", &n, &m);
  flow.init(n);

  int a, b, c;
  for(int i = 1; i <= m; i++) {
    scanf("%d %d %d", &a, &b, &c);
    flow.addEdge(a, b, c);
  }
}

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

  Flow flow;
  read(flow);
  int maxFlow = flow.maxFlow();
  printf("%d", maxFlow);

  return 0;
}