Cod sursa(job #1253003)

Utilizator gabrieligabrieli gabrieli Data 31 octombrie 2014 18:04:51
Problema Cuplaj maxim de cost minim Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 3.44 kb
#include <algorithm>
#include <fstream>
#include <limits>
#include <queue>
#include <utility>
#include <vector>
using namespace std;

const int INF = numeric_limits<int>::max();

int bellman_ford(
        const int source,
        const int sink,
        vector<int>& tree,
        vector<int>& D,
        const vector<vector<int>>& capacity,
        const vector<vector<int>>& weight,
        const vector<vector<int>>& rG) {
    fill(tree.begin(), tree.end(), -1);
    fill(D.begin(), D.end(), INF);
    queue<int> Q;
    vector<bool> inQ(rG.size(), false);
    
    Q.push(source);
    inQ[source] = true;
    tree[source] = source;
    D[source] = 0;
    
    while (!Q.empty()) {
        int u = Q.front(); Q.pop();
        inQ[u] = false;
        
        for (int v : rG[u])
            if (capacity[u][v] && D[v] > D[u] + weight[u][v]) {
                D[v] = D[u] + weight[u][v];
                tree[v] = u;
                if (!inQ[v]) {
                    Q.push(v);
                    inQ[v] = true;
                }
            }
    }
    return D[sink];
}

inline void augmentFlow(
        vector<int>& matching,
        const int flow,
        int v,
        const vector<int>& tree,
        vector<vector<int>>& capacity) {
    int nu = matching.size() - 1;
    for (int u = tree[v]; u != v; v = u, u = tree[v]) {
        capacity[u][v] -= flow;
        capacity[v][u] += flow;
        
        if ((0 < u && u <= nu) && (nu < v && v < tree.size() - 1)) {
            matching[u] = v - nu;
        }
    }
}

pair<int, int> minCostMaxFlow(
        const int source,
        const int sink,
        vector<int>& matching,
        vector<vector<int>>& capacity,
        const vector<vector<int>>& weight,
        const vector<vector<int>>& rG) {
    int flow = 0, cost = 0;
    vector<int> tree(rG.size());
    vector<int> D(rG.size());
    
    while (true) {
        int path_cost = bellman_ford(source, sink, tree, D, capacity, weight, rG);
        if (tree[sink] == -1) break;

        augmentFlow(matching, 1, sink, tree, capacity);
        
        flow++;
        cost += path_cost;
    }
    return make_pair(flow, cost);
}        

int main() {
    ifstream fin("cmcm.in");
    ofstream fout("cmcm.out");
    
    int NU, NV, edges; fin >> NU >> NV >> edges;
    int source = 0, sink = NU + NV + 1, N = NU + NV + 2;
    
    // residual graph and residual capacity
    vector<vector<int>> rG(N), capacity(N, vector<int>(N, 0)),
                        weight(N, vector<int>(N, 0));
    
    // necessary because of stupid, stupid output format for this problem :(
    vector<int> matching(NU+1, 0);
    vector<vector<int>> edge_index(NU+1, vector<int>(NV+1, 0)); 
    
    for (int u, v, z, i = 1; edges; --edges, ++i) {
        fin >> u >> v >> z;
        edge_index[u][v] = i;
        
        v += NU;
        rG[u].push_back(v);      capacity[u][v] = 1;
        rG[v].push_back(u);
        weight[u][v] = z;
        weight[v][u] = -z;
        // add edges in the residual graph to the source and the sink
        rG[source].push_back(u); capacity[source][u] = 1;
        rG[u].push_back(source);
        rG[v].push_back(sink);   capacity[v][sink] = 1;
        rG[sink].push_back(v);
    }
    
    pair<int, int> result = minCostMaxFlow(source, sink, matching, capacity, weight, rG);
    
    fout << result.first << ' ' << result.second << '\n';
    for (int u = 1; u <= NU; ++u) if (matching[u])
        fout << edge_index[u][matching[u]] << ' ';
    fout << endl;
       
    return 0;
}