Cod sursa(job #1110315)

Utilizator toranagahVlad Badelita toranagah Data 17 februarie 2014 22:53:53
Problema Algola Scor 10
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.09 kb
//Problem algola from Infoarena
#include <cmath>
#include <cstdint>

#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <queue>
#include <vector>
using namespace std;

ifstream fin("algola.in");
ofstream fout("algola.out");

const int8_t INF = 1 << 7;
const int MAX_K = 55;
const int MAX_N = 5005;

int N, M, K;
vector<pair<int, int>> edges[MAX_K];
vector<int> graph[MAX_N];
int8_t cap[MAX_N][MAX_N];
int8_t flow[MAX_N][MAX_N];
int source, sink;

void read_input();
void solve();
int maxflow();
bool find_augmenting_path(int father[]);
void add_edge(int a, int b, int c);
int hash_node(int n, int c);
void add_flow(int a, int b, int f);
int cp(int a, int b);

int main() {
    read_input();
    solve();
    return 0;
}

void read_input() {
    fin >> N >> M;

    source = 1;
    for (int i = 1, x; i <= N; i += 1) {
        fin >> x;
        K += x;
        add_edge(source, hash_node(i, 1), x);
    }

    for (int i = 1, a, b, c; i <= M; i += 1) {
        fin >> a >> b >> c;
        edges[a].push_back(make_pair(b, c));
        edges[b].push_back(make_pair(a, c));
    }
}

void solve() {
    int cost = 1;
    sink = hash_node(1, cost);

    while (maxflow() < K) {
        for (int i = 1; i <= N; i += 1) {
            int node = hash_node(i, cost);
            int higher = hash_node(i, cost + 1);
            add_edge(node, higher, INF);

            for (auto x: edges[i]) {
                add_edge(node, hash_node(x.first, cost + 1), x.second);
            }
        }

        cost += 1;
        sink = hash_node(1, cost);
    }

    fout << cost - 2;
}

inline void add_edge(int a, int b, int c) {
    graph[a].push_back(b);
    graph[b].push_back(a);
    cap[a][b] = c;
}

inline int hash_node(int n, int c) {
    return (c * MAX_K + n);
}

inline pair<int, int> dehash_node(int n) {
    return make_pair(n % MAX_K, N / MAX_K);
}

int maxflow() {
    static int result = 0;

    int father[MAX_N];
    while (find_augmenting_path(father)) {
        for (auto x: graph[sink]) {
            if (father[x] == 0 || cp(x, sink) == 0) continue;

            int new_flow = cp(x, sink);
            for (int node = x; node != source; node = father[node]) {
                new_flow = min(new_flow, cp(father[node], node));
            }

            add_flow(x, sink, new_flow);
            for (int node = x; node != source; node = father[node]) {
                add_flow(father[node], node, new_flow);
            }
            result += new_flow;
        }
    }
    return result;
}

bool find_augmenting_path(int father[]) {
    fill(father, father + MAX_N, 0);
    father[source] = source;
    queue<int> q;
    q.push(source);

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

        if (node == sink) return true;

        for (auto next: graph[node]) {
            if (father[next] == 0 && cp(node, next) > 0) {
                father[next] = node;
                q.push(next);
            }
        }
    }
    return false;
}

inline void add_flow(int a, int b, int f) {
    flow[a][b] += f;
    flow[b][a] -= f;
}

inline int cp(int a, int b) {
    return cap[a][b] - flow[a][b];
}