#include <iostream>
#include <vector>
using namespace std;

template <typename T>
struct Edge
{
    int to;
    T cap;
    int rev;
};

template <typename T>
struct Node
{
    T value;
    Node<T> *left;
    Node<T> *right;
};

template <typename T>
struct List
{
    Node<T> *first;
    Node<T> *last;
    int size;
    
    List() : first(nullptr), last(nullptr), size(0) {}
    
    void insert(Node<T> *node){
        if(size == 0){
            first = node;
            last = node;
            node->right = node;
            node->left = node;
        }
        else{
            node->right = first;
            node->left = last;
            first = node;
        }
        size++;
    }
    
    Node<T> *insert(T value){
        Node<T> *node;
        node = new Node<T>;
        node->value = value;
        insert(node);
        return node;
    }
    
    Node<T> *erase(Node<T> *node){
        if(size == 1){
            first = nullptr;
            last = nullptr;
            size--;
            return nullptr;
        }
        else{
            if(node == first) first = node->right;
            if(node == last) last = node->left;
            node->left->right = node->right;
            node->right->left = node->left;
            size--;
            return node->right;
        }
    }
};

template <typename T>
struct Flow
{
    int n;
    int r;
    int s;
    vector<vector<Edge<T>>> g;
    vector<int> label;
    vector<int> f;
    vector<int> itr;
    vector<Node<int>*> ptr;
    vector<List<int>> d;
    
    Flow(int n) : n(n){
        g.resize(n);
        label.resize(n);
        f.resize(n);
        itr.resize(n);
        ptr.resize(n);
        d.resize(n * 2 + 1);
    }
    
    void add_edge(int from, int to, T cap){
        g[from].push_back((Edge<T>){to, cap, (int)g[to].size()});
        g[to].push_back((Edge<T>){from, 0, (int)g[from].size() - 1});
    }
    
    void relabel(int u){
        d[label[u]].erase(ptr[u]);
        label[u]++;
        d[label[u]].insert(ptr[u]);
        itr[u] = 0;
    }
    
    void activate(int u){
        d[label[u]].insert(ptr[u]);
    }
    
    void inactivate(int u){
        d[label[u]].erase(ptr[u]);
    }
    
    void push(int u, Edge<T> &e, T df){
        if(df == 0) return;
        int v = e.to;
        if(f[v] == 0 && v != r && v != s) activate(v);
        e.cap -= df;
        g[v][e.rev].cap += df;
        f[v] += df;
        f[u] -= df;
        if(f[u] == 0) inactivate(u);
    }
    
    void process(int u){
        for(int &i = itr[u]; i < (int)g[u].size(); i++){
            Edge<T> &e = g[u][i];
            if(label[e.to] < label[u]) push(u, e, min(f[u], e.cap));
            if(f[u] == 0) break;
        }
        if(f[u]) relabel(u);
    }
    
    int max_flow(int r_, int s_){
        r = r_;
        s = s_;
        for(int i = 0; i < n; i++){
            ptr[i] = new Node<T>;
            ptr[i]->value = i;
        }
        label[r] = n;
        for(Edge<T> &e : g[r]){
            push(r, e, e.cap);
        }
        int h = 0;
        while(h >= 0){
            if(d[h].size == 0){
                h--;
                continue;
            }
            int u = d[h].first->value;
            process(u);
            h++;
        }
        return f[s];
    }
};

int main()
{
    int n, m;
    cin >> n >> m;
    Flow<int> f(n);
    for(int i = 0; i < m; i++){
        int u, v, c;
        cin >> u >> v >> c;
        f.add_edge(u, v, c);
    }
    cout << f.max_flow(0, n - 1) << endl;
}



Measured memory_bytes: 3148