Cod sursa(job #1759266)

Utilizator Al3ks1002Alex Cociorva Al3ks1002 Data 18 septembrie 2016 19:01:11
Problema Cuplaj maxim de cost minim Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.95 kb
#include <stdio.h>
#include <bits/stdc++.h>

using namespace std;

// Class that represents a directed graph where you
// can find the min cost max flow with Bellman-Ford.
// Memory complexity: O(number_of_vertices ^ 2).
template<class F, class C>
class MinCostMaxFlowGraph {
    public:
        MinCostMaxFlowGraph(int num_vertices) : num_vertices_(num_vertices + 1) {
            previous_vertex_.resize(num_vertices_);
            distance_.resize(num_vertices_);
        }

        void AddEdge(int from, int to, F capacity, C cost, int index) {
            neighbours_[from].push_back(to);
            capacity_[from][to] += capacity;
            cost_[from][to] += cost;
            neighbours_[to].push_back(from);
            cost_[to][from] -= cost;
            index_[from][to] = index;
        }

        pair<F, C> GetMinCostMaxFlow(int source, int sink) {
            F max_flow = 0;
            C min_cost = 0;
            while (PushFlow(source, sink)) {
                F flow_added = numeric_limits<F>::max();

                int current_vertex = sink;
                while (current_vertex != source) {
                    int previous_vertex = previous_vertex_[current_vertex];
                    flow_added = min(flow_added, capacity_[previous_vertex][current_vertex]
                                     - flow_[previous_vertex][current_vertex]);
                    current_vertex = previous_vertex_[current_vertex];
                }

                current_vertex = sink;
                while (current_vertex != source) {
                    int previous_vertex = previous_vertex_[current_vertex];
                    flow_[previous_vertex][current_vertex] += flow_added;
                    flow_[current_vertex][previous_vertex] -= flow_added;
                    current_vertex = previous_vertex_[current_vertex];
                }

                max_flow += flow_added;
                min_cost += distance_[sink] * flow_added;
            }
            return make_pair(max_flow, min_cost);
        }

        F GetFlow(int from, int to) {
            return flow_[from][to];
        }

        int GetIndex(int from, int to) {
            return index_[from][to];
        }

    private:
        bool PushFlow(int source, int sink) {
            fill(previous_vertex_.begin(), previous_vertex_.end(), -1);
            fill(distance_.begin(), distance_.end(), numeric_limits<C>::max());
            vector<bool> in_queue(num_vertices_, false);
            queue<int> q;

            distance_[source] = 0;
            in_queue[source] = true;
            q.push(source);

            while (!q.empty()) {
                int vertex = q.front();
                q.pop();
                in_queue[vertex] = false;

                if (vertex == sink) {
                    continue;
                }

                for (int neighbour : neighbours_[vertex]) {
                    F edge_capacity = capacity_[vertex][neighbour];
                    F edge_flow = flow_[vertex][neighbour];
                    C edge_cost = cost_[vertex][neighbour];

                    if (distance_[vertex] + edge_cost < distance_[neighbour]
                            && edge_flow < edge_capacity) {
                        distance_[neighbour] = distance_[vertex] + edge_cost;
                        previous_vertex_[neighbour] = vertex;
                        if (!in_queue[neighbour]) {
                            in_queue[neighbour] = true;
                            q.push(neighbour);
                        }
                    }
                }
            }

            return distance_[sink] != numeric_limits<C>::max();
        }

        static const int kMax = 605;
        int num_vertices_;
        vector<int> neighbours_[kMax];
        F capacity_[kMax][kMax];
        F flow_[kMax][kMax];
        C cost_[kMax][kMax];
        int index_[kMax][kMax];
        vector<int> previous_vertex_;
        vector<C> distance_;
};

int main() {
    clock_t start = clock();
    cin.sync_with_stdio(false);

    ifstream cin("cmcm.in");
    ofstream cout("cmcm.out");

    int n, m, e;
    cin >> n >> m >> e;

    MinCostMaxFlowGraph<int, int> graph(n + m + 1);
    for (int i = 1; i <= e; i++) {
        int from, to, cost;
        cin >> from >> to >> cost;
        to += n;
        graph.AddEdge(from, to, 1, cost, i);
    }

    int source = 0;
    int sink = n + m + 1;

    for (int i = 1; i <= n; i++) {
        graph.AddEdge(source, i, 1, 0, 0);
    }

    for (int i = n + 1; i <= n + m; i++) {
        graph.AddEdge(i, sink, 1, 0, 0);
    }

    pair<int, int> min_cost_max_flow = graph.GetMinCostMaxFlow(source, sink);
    cout << min_cost_max_flow.first << " " << min_cost_max_flow.second << '\n';

    for (int i = 1; i <= n; i++) {
        for (int j = n + 1; j <= n + m; j++) {
            if (graph.GetFlow(i, j)) {
                cout << graph.GetIndex(i, j) << " ";
            }
        }
    }

    clock_t finish = clock();
    cerr << fixed << 1.0 * (finish - start) / CLOCKS_PER_SEC << endl;

    return 0;
}