Cod sursa(job #2693195)

Utilizator CraniXortDumitrescul Eduard CraniXort Data 5 ianuarie 2021 09:33:33
Problema Flux maxim de cost minim Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.55 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>

std::ifstream fin("fmcm.in");
std::ofstream fout("fmcm.out");

class Graph{
    private:
        int V, source, sink;
        std::vector <std::vector <int>> edge;
        std::vector <std::vector <int>> cap;
        std::vector <std::vector <int>> cost;
        std::vector <int> dist;
        std::vector <int> parent, bellman;
        std::vector <bool> visited;

        void addAuxNode(){
            for(int node=1; node<=V; node++)
                edge[V+1].push_back(node),
                cap[V+1][node] = 1,
                cost[V+1][node] = 0;
        }

        void recreateGraph(){
            for(int node=1; node<=V; node++){
                for(int& next: edge[node])
                    cost[node][next] = cost[node][next] + bellman[node] - bellman[next];
            }
        }

        void printGraph(){
            for(int node=1; node<=V; node++){
                for(int& next: edge[node])
                    fout << node << ' ' << next << ' ' << cap[node][next] << ' ' << cost[node][next] << '\n';
                fout << '\n';
            }
        }

        bool bfs(){
            std::queue <int> q;
            std::fill(visited.begin(), visited.end(), false);
            visited[source] = true;
            q.push(source);

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

                if(node == sink) continue;

                for(auto& next: edge[node]){
                    if(visited[next] == false and cap[node][next] > 0){
                        visited[next] = true;
                        q.push(next);
                        parent[next] = node;
                    }
                }
            }

            return visited[sink];
        }
        bool dijkstra(int src, int dest){
            std::priority_queue <std::pair <int, int>, std::vector <std::pair <int, int>>, std::greater <std::pair <int, int>>> pq;
            std::fill(visited.begin(), visited.end(), false);
            std::fill(dist.begin(), dist.end(), 1e8);
            dist[src] = 0;
            visited[src] = true;
            pq.push({0, src});
            while(pq.empty() == false){
                int node = pq.top().second;
                int c = pq.top().first;
                pq.pop();
                if(dist[node] < c) continue;
                if(node == dest) continue;

                for(int& next: edge[node]){
                    if(dist[next] > dist[node] + cost[node][next] and cap[node][next] > 0){
                        dist[next] = dist[node] + cost[node][next];
                        pq.push({dist[next], next});
                        visited[next] = true;
                        parent[next]  = node;
                    }
                }
            }

            return visited[dest];
        }

    public:
        Graph(int size){
            V = size;
            edge.resize(V+2);
            cap.resize(V+2);
            for(auto& line: cap)
                line.resize(V+2);
            cost.resize(V+2);
            for(auto& line: cost)
                line.resize(V+2);
        }

        void addEdge(int src, int dest, int capacity, int weight){
            edge[src].push_back(dest);
            edge[dest].push_back(src);
            cap[src][dest] = capacity;
            cost[src][dest] = weight;
            cost[dest][src] = -weight;
        }

        int maxFlow(int src, int dest){
            source = src;
            sink = dest;

            parent.resize(V+2);
            visited.resize(V+2);

            int maxFlow = 0, flow;
            while(bfs() == true){
                for(int& node: edge[sink]){
                    if(visited[node] == true and cap[node][sink] > 0){
                        parent[sink] = node;
                        flow = 1e9;
                        for(int curr = sink; curr != source; curr = parent[curr])
                            flow = std::min(flow, cap[parent[curr]][curr]);
                        for(int curr = sink; curr != source; curr = parent[curr]){
                            cap[parent[curr]][curr] -= flow;
                            cap[curr][parent[curr]] += flow;
                        }
                        maxFlow += flow;
                    }
                }
            }

            return maxFlow;
        }

        void bellmanFord(int src){
            bellman.resize(V+2);
            std::fill(bellman.begin(), bellman.end(), 1e8);
            bellman[src] = 0;

            for(int count=1; count<V; count++){
                for(int node=1; node<=V+1; node++)
                for(int& next: edge[node])
                    if(cap[node][next] > 0)
                        bellman[next] = std::min(bellman[next], bellman[node] + cost[node][next]);
            }

            // for(int node=1; node<=V; node++)
            //     fout << bellman[node] << '\n';
        }

        int minCostMaxFlow(int src, int dest){
            source = src;
            sink = dest;

            visited.resize(V+2);
            parent.resize(V+2);
            dist.resize(V+2);

            addAuxNode();
            bellmanFord(V+1);
            recreateGraph();
            //printGraph();

            int maxFlow = 0, minCost = 0, flow;

            while(dijkstra(source, sink) == true){
                for(int &it: edge[sink]){
                    if(visited[it] == true and dist[sink] == dist[it] + cost[it][sink]  and cap[it][sink] > 0){
                        flow = 1e8;
                        parent[sink] = it;
                        for(int node = sink; node != source and flow; node = parent[node])
                            flow = std::min(flow, cap[parent[node]][node]);
                        for(int node = sink; node != source and flow; node = parent[node]){
                            cap[parent[node]][node] -= flow;
                            cap[node][parent[node]] += flow;
                            minCost += flow * (cost[parent[node]][node] - bellman[parent[node]] + bellman[node]);
                        }
                        maxFlow += flow;
                    }
                }
                
            }
            //fout << maxFlow << '\n';
            return minCost;
        }

};



void readInput(){
    int V, E, source, sink;
    fin >> V >> E >> source >> sink;
    Graph graph(V);
    for(int i=0, src, dest, cap, weight; i<E; i++){
        fin >> src >> dest >> cap >> weight;
        graph.addEdge(src, dest, cap, weight);
    }
    //graph.bellmanFord(1);
    fout << graph.minCostMaxFlow(source, sink);
}

int main(){
    readInput();
    return 0;
}