#include <bits/stdc++.h>

using namespace std;

namespace {

    /** whole range */
    #define whole(xs) (xs).begin(), (xs).end()
    /** output whole vector. ex) vector<int>{1, 2, 3} -> '1 2 3'. */
    template<typename T>
    ostream& operator<<(ostream& os, const vector<T>& xs) {
       if (xs.empty()) return os;
       os << xs[0];
       for (auto i = 1; i < xs.size(); i++) os << ' ' << xs[i];
       return os;
    }
    struct Network {
        const int INF = 1<<28;
        // ???????????????????????? ?¬¬?????? 8.5?????????
        struct Edge {
            int from, to, cap;
            Edge* rev;
            Edge(int from, int to, int cap) :
                from(from), to(to), cap(cap) {}
        };
        vector<Edge*> edges, rev_edges;
        vector<vector<Edge*>> graph;
        Network(int N) : graph(N, vector<Edge*>()) {}
        ~Network() { 
            for (auto e : edges) delete(e);
            for (auto r : rev_edges) delete(r);
        }
        void addEdge(int s, int t, int cap) {
            auto e = new Edge(s, t, cap);
            auto r = new Edge(t, s, 0);
            edges.push_back(e); rev_edges.push_back(r);
            e->rev = r; r->rev = e;
            graph[s].push_back(e); graph[t].push_back(r);
        }
        int maxFlow(int s, int t) {
            const int N = graph.size();
            vector<int> phi(N, 0); phi[s] = N; // phi : distance labeling
            vector<int> excess(N, 0);
            queue<int> activePoints;
            for (auto e : graph[s]) {
                auto gamma = e->cap;
                e->cap = 0;
                e->rev->cap = gamma;
                excess[e->from] -= gamma;
                excess[e->to] += gamma;
                activePoints.push(e->to);
            }
            auto push = [&](Edge* e) {
                //cout << "push " << e->from << " " << e->to << "(" << e->cap << ")"<< endl;
                auto gamma = min(excess[e->from], e->cap);
                e->cap -= gamma;
                e->rev->cap += gamma;
                excess[e->from] -= gamma;
                excess[e->to] += gamma;
            };
            auto relabel = [&](int v) {
                //cout << "relabel" << endl;
                phi[v] = INF;
                for (auto e : graph[v]) {
                    if (e->cap <= 0) continue;
                    int w = e->to;
                    phi[v] = min(phi[v], phi[w] + 1);
                };
            };
            while (not activePoints.empty()) {
                auto v = activePoints.front(); activePoints.pop();
                //cout << "v: " << v << endl;
                //cout << "excess: " << excess << endl;
                //cout << "phi: " << phi << endl;
                bool used = false;
                for (auto e : graph[v]) {
                    if (phi[e->from] == phi[e->to] + 1 and e->cap > 0) {
                        used = true;
                        push(e);
                    }
                }
                if (not used) {
                    relabel(v);
                }
                queue<int> nactive;
                for (int i = 0; i < N; i++) if (i != t and i != s and excess[i] > 0) nactive.push(i);
                activePoints = nactive;
            }
            int ans = 0;
            for (auto r : rev_edges) {
                ans += r->cap;
            }
            //cout << excess << endl;
            //cout << phi << endl;
            //for (auto r : rev_edges) {
            //    cout << r->to << " -> " << r->from << " : " << r->cap << endl;
            //}
            return excess[t];
        }
    };

    int V, E;
    Network *g;
    void input() {
        cin >> V >> E;
        g = new Network(V);
        for (auto i = 0; i < E; i++) {
            int u, v, c;
            cin >> u >> v >> c;
            g->addEdge(u, v, c);
        }
    }

    void solve() {
        cout << g->maxFlow(0, V - 1) << endl;
        delete(g);
    }
}

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

Measured memory_bytes: 3232