Cod sursa(job #3136697)

Utilizator DavidLDavid Lauran DavidL Data 7 iunie 2023 20:24:42
Problema Flux maxim de cost minim Scor 50
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.97 kb
#include <bits/stdc++.h>
using namespace std;
ifstream fin("fmcm.in");
ofstream fout("fmcm.out");

const int NMAX = 355;
const int INF = 1e9;

int n, m, src, dest;
int cost[NMAX][NMAX];
int cap[NMAX][NMAX], flow[NMAX][NMAX];
vector<pair<int, int>> G[NMAX], invG[NMAX];
int prevNode[NMAX];  // for bfs (negative if inverse edge)
int dist[NMAX];

// returns whether we reached the end
bool bellmanFord() {
    for (int i = 1; i <= n; i++) {
        prevNode[i] = 0;
        dist[i] = INF;
    }

    queue<int> Q;  // TODO check if it's in the queue before pushing (optimization)
    dist[src] = 0;
    Q.push(src);
    while (!Q.empty()) {
        int vertex = Q.front();
        Q.pop();

        // normal edges
        for (auto neigh: G[vertex])
            if (dist[vertex] + neigh.second < dist[neigh.first] && flow[vertex][neigh.first] != cap[vertex][neigh.first]) {  // unvisited vertex, and unsaturated edge
                dist[neigh.first] = dist[vertex] + neigh.second;
                prevNode[neigh.first] = vertex;
                Q.push(neigh.first);
            }
        
        // inverse edges
        for (auto neigh: invG[vertex])
            if (dist[vertex] - neigh.second < dist[neigh.first] && flow[neigh.first][vertex] != 0) {  // we'll remove flow from here
                // TODO shouldnt dist be subtracted here?
                dist[neigh.first] = dist[vertex] - neigh.second;
                prevNode[neigh.first] = -vertex;
                Q.push(neigh.first);
            }
    }
    return dist[dest] != INF;
}

int main() {
    fin >> n >> m >> src >> dest;
    for (int i = 1; i <= m; i++) {
        int u, v, ca, co;
        fin >> u >> v >> ca >> co;
        G[u].push_back({v, co});
        invG[v].push_back({u, co});

        cap[u][v] = ca;
        cost[u][v] = co;
        flow[u][v] = 0;
    }

    int totalCost = 0;
    while (bellmanFord()) {
        int curr = dest;

        int toAdd = cap[prevNode[dest]][dest] - flow[prevNode[dest]][dest];
        while (curr != src) {
            int a = prevNode[curr], b = curr;
            if (a < 0) {  // inverse edge
                toAdd = min(toAdd, flow[b][-a]);
                curr = -a; 
            }
            else {
                toAdd = min(toAdd, cap[a][b] - flow[a][b]);
                curr = a;
            }
        }

        toAdd = 1;  // EVIL
        
        curr = dest;
        while (curr != src) {
            int a = prevNode[curr], b = curr;

            if (a < 0) {
                flow[b][-a] -= toAdd;
                totalCost -= toAdd * cost[b][-a];  // TODO subtract or add?
                curr = -a;
            }
            else {
                flow[a][b] += toAdd;
                totalCost += toAdd * cost[a][b];
                curr = a;
            }
        }
    }

    int totalFlow = 0;
    for (auto v: G[src])
        totalFlow += flow[src][v.first];
    fout << totalCost;

    return 0;
}