#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define ar array
#define vt vector
#define pq priority_queue
#define pu push
#define pub push_back
#define em emplace
#define emb emplace_back
#define mt make_tuple
#define all(x) x.begin(), x.end()
#define allr(x) x.rbegin(), x.rend()
#define allp(x, l, r) x.begin() + l, x.begin() + r
#define len(x) (int)x.size()
#define uniq(x) unique(all(x)), x.end()
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
template <class T, size_t N>
void re(array <T, N>& x);
template <class T>
void re(vt <T>& x);
template <class T>
void re(T& x) {
cin >> x;
}
template <class T, class... M>
void re(T& x, M&... args) {
re(x); re(args...);
}
template <class T>
void re(vt <T>& x) {
for(auto& it : x)
re(it);
}
template <class T, size_t N>
void re(array <T, N>& x) {
for(auto& it : x)
re(it);
}
template <class T, size_t N>
void wr(array <T, N> x);
template <class T>
void wr(vt <T> x);
template <class T>
void wr(T x) {
cout << x;
}
template <class T, class ...M> void wr(T x, M... args) {
wr(x), wr(args...);
}
template <class T>
void wr(vt <T> x) {
for(auto it : x)
wr(it, ' ');
}
template <class T, size_t N>
void wr(array <T, N> x) {
for(auto it : x)
wr(it, ' ');
}
void set_fixed(int p = 0) {
cout << fixed << setprecision(p);
}
void set_scientific() {
cout << scientific;
}
inline void Open(const string Name) {
#ifndef ONLINE_JUDGE
(void)!freopen((Name + ".in").c_str(), "r", stdin);
(void)!freopen((Name + ".out").c_str(), "w", stdout);
#endif
}
const ll INF = 1e18;
struct Dinic {
struct edge {
int to, rev;
ll flow, w;
int id;
};
int n, s, t, mxid;
vt <int> d, flow_through;
vt <int> done;
vt <vt <edge>> g;
Dinic() {
}
Dinic(int _n) {
n = _n + 10;
mxid = 0;
g.resize(n);
}
void add_edge(int u, int v, ll w, int id = -1) {
edge a = {v, len(g[v]), 0, w, id};
edge b = {u, len(g[u]), 0, 0, -2}; //for bidirectional edges cap(b) = w
g[u].emb(a);
g[v].emb(b);
mxid = max(mxid, id);
}
bool bfs() {
d.assign(n, -1);
d[s] = 0;
queue <int> q;
q.pu(s);
while(!q.empty()) {
int u = q.front();
q.pop();
for(auto &e : g[u]) {
int v = e.to;
if(d[v] == -1 && e.flow < e.w)
d[v] = d[u] + 1, q.pu(v);
}
}
return d[t] != -1;
}
ll dfs(int u, ll flow) {
if (u == t) {
return flow;
}
for(int &i = done[u]; i < len(g[u]);i++) {
edge &e = g[u][i];
if(e.w <= e.flow)
continue;
int v = e.to;
if(d[v] == d[u] + 1) {
ll nw = dfs(v, min(flow, e.w - e.flow));
if(nw > 0) {
e.flow += nw;
g[v][e.rev].flow -= nw;
return nw;
}
}
}
return 0;
}
ll max_flow(int _s, int _t) {
s = _s;
t = _t;
ll flow = 0;
while (bfs()) {
done.assign(n, 0);
while(ll nw = dfs(s, INF)) {
flow += nw;
}
}
flow_through.assign(mxid + 10, 0);
for(int i = 0; i < n; i++)
for(auto e : g[i])
if(e.id >= 0)
flow_through[e.id] = e.flow;
return flow;
}
};
void solve() {
/* to be explained */
int n, m; re(n, m);
Dinic FG(n);
for (int i = 0; i < m; ++i) {
int u, v, m; re(u, v, m);
--u, --v;
FG.add_edge(u, v, m);
}
wr(FG.max_flow(0, n - 1));
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
Open("maxflow");
int t = 1;
for(;t;t--) {
solve();
}
return 0;
}