#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int INF = 1e9;

struct Edge {
    int from, to, cap, flow;
    Edge(int from, int to, int cap, int flow):from(from), to(to), cap(cap), flow(flow){}   
};

struct Dinic {
    int n;
    vector<Edge> edges;
    vector<vector<int>> g;
    
    vector<int> d; //depth of a node
    int flow = 0;
    
    Dinic(int n) : n(n) {
        g.assign(n + 1, vector<int>());
    }
    
    void addEdge(int from, int to, int cap) {
        edges.push_back(Edge(from , to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        g[from].push_back(edges.size() - 2);
        g[to].push_back(edges.size() - 1);   
    }
    
    

    int solve1(int s, int t) {
       while (bfs(s, t)) {
           vector<int> cur(n + 1, 0);
           int f;
           while ((f = dfs1(s, INF, t, cur)) > 0) {
                flow += f;
           }
       }
       return flow;
    }
    
   
    int solve(int s, int t) {
       while (bfs(s, t)) {
           vector<int> cur(n + 1, 0);
           flow += dfs(s, INF, t, cur);
       }
       return flow;
    }
    
    
    bool bfs(int s, int t) {
        d.assign(n + 1, 0); //depth
        
        vector<bool> vis(n + 1, false);
        queue<int> q;
        d[s] = 0;
        vis[s] = true;
        q.push(s);
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (int edgeId : g[u]) {
                Edge e = edges[edgeId];
                if (!vis[e.to] && e.cap > e.flow) {
                    vis[e.to] = true;
                    d[e.to] = d[u] + 1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    
    
    int dfs(int u, int a,  int t, vector<int>& cur) {
        if (u == t || a == 0) {
            return a;
        }
        int currentFlow = 0, f;
        for (int& i = cur[u]; i < g[u].size(); i++) {
           Edge& e = edges[g[u][i]];
           if (d[u] + 1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow), t,cur)) > 0) {
               e.flow += f;
               edges[(g[u][i] ^ 1)].flow -= f;
               currentFlow += f;
               a -= f;
               if (a == 0) {
                   break;
               }
           }
        }
        return currentFlow;
    }
    
 
    int dfs1(int u, int f, int t, vector<int>& cur) {
        if (u == t) {
            return f;
        }
        for (int& i = cur[u]; i < g[u].size(); i++) {
           Edge& e = edges[g[u][i]];
           if (e.cap > e.flow && d[u] < d[e.to]) {
               int f1 = dfs(e.to, min(f, e.cap - e.flow), t, cur);
               if (f1 > 0) {
                    e.flow += f1;
                    edges[(g[u][i] ^ 1)].flow -= f1;
                    return f1;
               }
           }
        }
        return 0;
    }
    
};

int main() {
    int v, e, s, t;
    //cin >> v >> e >> s >> t;
    cin >> v >> e;
    s = 0;
    t = v - 1;
    Dinic maxflow(v);
    for (int i = 0; i < e; i++) {
        int from, to, cap;
        cin >> from >> to >> cap;
        maxflow.addEdge(from, to, cap);
    }
    int ans = maxflow.solve1(s, t);
    cout << ans << endl;
    
    return 0;
}

Measured memory_bytes: 3244