Cod sursa(job #1870534)

Utilizator msciSergiu Marin msci Data 6 februarie 2017 18:50:50
Problema Cuplaj maxim de cost minim Scor 60
Compilator cpp Status done
Runda Arhiva educationala Marime 5.93 kb
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <string>
#include <sstream>
#include <algorithm>
#include <vector>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <random>
#include <tuple>
#include <limits>
#include <functional>
#include <complex>
#include <bitset>
#include <list>

//#include <atomic>
//#include <condition_variable>
//#include <future>
//#include <mutex>
//#include <thread>

using namespace std;

#define debug(x) cerr << #x << " = " << x << "\n"

const int INF           = 0x3f3f3f3f;
const long long INFL    = 0x3f3f3f3f3f3f3f3fLL;

struct MinCostFlow
{
    typedef long long Flow; typedef long long Cost; typedef int Index;
    
    static const Flow InfCapacity = 0x3f3f3f3f / 2;
    static const Cost InfCost = 0x3f3f3f3f / 2;

    int index;

    struct Edge
    {
        Index to, rev;
        Flow capacity;
        Cost cost;
        Index id;
    };

    vector< vector<Edge> > g;

    void init(int n) { index = 0; g.assign(n, vector<Edge>()); }

    void add(Index i, Index j, Flow capacity = InfCapacity, Cost cost = Cost())
    {
        Edge e, f;
        e.id = ++index;
        e.to = j, f.to = i;
        e.capacity = capacity, f.capacity = 0;
        e.cost = cost, f.cost = -cost;
        g[i].push_back(e), g[j].push_back(f);
        g[i].back().rev = (int) g[j].size() - 1;
        g[j].back().rev = (int) g[i].size() - 1;
    }

    void addB(Index i, Index j, Flow capacity = InfCapacity, Cost cost = Cost())
    {
        add(i, j, capacity, cost);
        add(j, i, capacity, cost);
    }

    pair<Cost, Flow> min_cost_flow(Index s, Index t, Flow f = InfCapacity, bool useSPFA = false)
    {
        Index n = (Index) g.size();

        vector<Cost> dist(n);
        vector<Cost> potential(n);
        vector<Index> prev(n);
        vector<Index> prev_edge(n);

        pair<Cost, Flow> total = {0, 0};

        while (f > 0)
        {
            fill(dist.begin(), dist.end(), InfCost);

            if (useSPFA || total.second == 0)
            {
                vector<bool> in_queue(n);
                deque<Index> q;
                q.push_back(s);
                dist[s] = 0;
                in_queue[s] = true;
                
                while (!q.empty())
                {
                    Index i = q.front();
                    q.pop_front();
                    in_queue[i] = false;
                    for (Index ei = 0; ei < (Index) g[i].size(); ei++)
                    {
                        const Edge& e = g[i][ei];
                        Index j = e.to;
                        Cost d = dist[i] + e.cost;
                        if (e.capacity > 0 && d < dist[j])
                        {
                            if (!in_queue[j])
                            {
                                in_queue[j] = true;
                                q.push_back(j);
                            }
                            dist[j] = d;
                            prev[j] = i;
                            prev_edge[j] = ei;
                        }
                    }
                }
            }
            else
            {
                vector<bool> visited(n, false);
                priority_queue< pair<Cost, Index>, vector< pair<Cost, Index> >, std::greater< pair<Cost, Index> > > q;

                q.push({0, s});
                dist[s] = 0;

                while (!q.empty())
                {
                    Index i = q.top().second;
                    q.pop();
                    if (visited[i]) continue;
                    visited[i] = true;

                    for (Index ei = 0; ei < (Index) g[i].size(); ei++)
                    {
                        const Edge& e = g[i][ei];
                        if (e.capacity <= 0) continue;
                        Index j = e.to;
                        Cost d = dist[i] + (e.cost + potential[i] - potential[j]);
                        if (d < dist[j])
                        {
                            dist[j] = d;
                            prev[j] = i;
                            prev_edge[j] = ei;
                            q.push({d, j});
                        }
                    }
                }
            }
            if (dist[t] == InfCost) break;
            if (!useSPFA) for (Index i = 0; i < n; i++) potential[i] += dist[i];

            Flow d = f;
            Cost dist_t = 0;

            for (Index v = t; v != s; )
            {
                Index u = prev[v];
                const Edge& e = g[u][prev_edge[v]];
                d = min(d, e.capacity);
                dist_t += e.cost;
                v = u;
            }

            f -= d;
            total.first += d * dist_t;
            total.second += d;

            for (Index v = t; v != s; )
            {
                Index u = prev[v];
                Edge& e = g[u][prev_edge[v]];
                e.capacity -= d;
                g[e.to][e.rev].capacity += d;
                v = u;
            }
        }
        return total;
    }
};

const long long MinCostFlow::InfCost;
const long long MinCostFlow::InfCapacity;

int main(int argc, char* argv[]) 
{
    freopen("cmcm.in", "r", stdin);
    freopen("cmcm.out", "w", stdout);
    cin.sync_with_stdio(false);
    int N, M, E;
    cin >> N >> M >> E;
    MinCostFlow mf;
    mf.init(N + M + 2);
    int s = 0, t = N + M + 1;
    for (int i = 0; i < E; i++)
    {
        int x, y, c;
        cin >> x >> y >> c;
        mf.add(x, y + N, 1, c);
    }
    for (int i = 1; i <= N; i++) mf.add(s, i, 1, 0);
    for (int i = N + 1; i <= N + M; i++) mf.add(i, t, 1, 0);
    auto ans = mf.min_cost_flow(s, t);
    auto& g = mf.g;
    cout << ans.second << " " << ans.first << "\n";
    for (int i = 1; i <= N; i++)
    {
        for (auto& e : g[i])
        {
            if (e.capacity == 0)
            {
                cout << e.id << " ";
                break;
            }
        }
    }
    cout << endl;
    return 0;
}