Cod sursa(job #3189917)

Utilizator vatau.lorenaVatau Lorena vatau.lorena Data 6 ianuarie 2024 17:46:29
Problema Cc Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.51 kb
#include <fstream>
#include <vector>
#include <queue>
#define E 100001
#define N 202

using namespace std;

ifstream fin("cc.in");
ofstream fout("cc.out");

// Structura pentru a reprezenta o muchie în graf
struct Edge {
    int to, cost, capacity, reverse_edge;
};

int n, totalCost = 0;
vector<Edge> graph[N];  // lista de adiacență a grafului
int dist[N], prevNode[N], prevEdge[N];

// Funcția pentru adăugarea unei muchii în graf
void addEdge(int u, int v, int cost) {
    graph[u].push_back({v, cost, 1, static_cast<int>(graph[v].size())});  // adăugarea muchiei
    graph[v].push_back({u, -cost, 0, static_cast<int>(graph[u].size()) - 1});
}

// Algoritmul Dijkstra pentru a găsi drumul cel mai scurt
bool dijkstra(int s, int t) {
    fill(dist, dist + N, E);  // inițializarea distanțelor cu o valoare mare
    dist[s] = 0;  // distanța de la sursă la sursă este 0
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    pq.push({0, s});  // adăugarea sursă în coadă
    while (!pq.empty()) {
        auto [d, u] = pq.top();  // extragerea nodului cu distanța minimă
        pq.pop();  // ștergerea nodului din coadă
        if (dist[u] < d) continue;  // dacă distanța curentă este mai mare, trecem la următorul nod
        for (int i = 0; i < graph[u].size(); ++i) {
            Edge &e = graph[u][i];
            int v = e.to;
            // verificăm dacă putem să ne deplasăm la v printr-o muchie neutilizată
            if (e.capacity > 0 && dist[v] > dist[u] + e.cost) {
                dist[v] = dist[u] + e.cost;  // actualizăm distanța
                prevNode[v] = u;  // nodul anterior
                prevEdge[v] = i;  // muchia anterioră
                pq.push({dist[v], v});  // adăugăm nodul în coada de priorități
            }
        }
    }
    return dist[t] != E;  // returnăm dacă există un drum până la destinație
}

// Algoritmul pentru calcularea fluxului maxim cu cost minim
int minCostMaxFlow(int s, int t) {
    int flow = 0;  // fluxul maxim
    while (dijkstra(s, t)) {
        int minFlow = E;  // fluxul minim posibil
        for (int v = t; v != s; v = prevNode[v]) {
            Edge &e = graph[prevNode[v]][prevEdge[v]];  // muchia curentă
            minFlow = min(minFlow, e.capacity);  // calculăm fluxul minim
        }
        for (int v = t; v != s; v = prevNode[v]) {
            Edge &e = graph[prevNode[v]][prevEdge[v]];  // muchia curentă
            e.capacity -= minFlow;  // reducem capacitatea
            graph[v][e.reverse_edge].capacity += minFlow;  // actualizăm capacitatea muchiei inverse
        }
        flow += minFlow;  // actualizăm fluxul
        totalCost += dist[t] * minFlow;  // calculăm costul total
    }
    return flow;  // returnăm fluxul maxim
}

// Funcția principală a programului
int main() {
    fin >> n;  // citim numărul de noduri
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            int k;
            fin >> k;
            addEdge(i, n + j + 1, k);  // adăugăm muchia în graf
        }
    }
    for (int i = 1; i <= n; ++i) {
        addEdge(0, i, 0);  // adăugăm muchia de la sursă la nodurile initiale cu cost 0
        addEdge(i + n + 1, n + 1, 0);  // adăugăm muchia de la nodurile finale la destinație cu cost 0
    }

    int maxFlow = minCostMaxFlow(0, n + 1);  // calculăm fluxul maxim
    fout << totalCost << "\n";
    fin.close();
    fout.close();
    return 0;
}