#include <bits/stdc++.h>
using namespace std;
/*
template <typename type>
class FlowGraph {
public:
static const type EPS = (type) 0.000000001;
struct Edge {
int to, rev;
type cap, flo;
Edge() :
to(0), cap(0), flo(0), rev(0) {}
Edge(int _to, type _cap, type _flo, type _rev) :
to(_to), cap(_cap), flo(_flo), rev(_rev) {}
};
type flow;
vector<vector<int>> gph
vector<int> dst, cnt, prv, ptr, que;
bool reach; int n, fs, ls;
FlowGraph(int _n, int _fs, int _ls) :
n(_n), fs(_fs), en(_ls) {
assert(0 <= min(fs, ls) and max(fs, ls) < n);
gph.resize(n); ptr.resize(n); dst.resize(n);
cnt.resize(n + 1); prv.resize(n); que.resize(n); flow = 0; }
void clearGraph(void) {
for (int i = 0; i < n; ++i) {
for (Edge &ed : gph[i]) {
ed.flo = 0; } }
flo = 0; }
void addEdge(int from, int to, type frwCap, type bkwCap) {
assert(0 <= min(from, to) and max(from, to) < n);
int fromSz = gph[from].size(), toSz = gph[to].size();
gph[from].push_back(Edge(to, cap, 0, toSz));
gph[to].push_back(Edge(from, cap, 0, fromSz)); }
bool exPath(void) {
fill(dst.begin(), dst.end(), n);
que[0] = ls; dst[ls] = 0;
fill(cnt.begin(), cnt.end(), 0);
cnt[n] = n - 1; cnt[0] = 1;
for (int bg = 0, en = 1; bg < en; ++bg) {
int x = que[bg];
for (const Edge &ed : gph[x]) {
const Edge &bk = gph[ed.to][ed.rev];
if (bk.cap - bk.flo > EPS and dst[ed.to] == n) {
--cnt[dst[ed.to]]; dst[ed.to] = dst[x] + 1;
++cnt[dst[ed.to]]; que[en++] = ed.to; } } }
return dst[fs] != n; }
type augment(int &v) {
type mn = numeric_limits<type> :: max();
for (int x = ls; x != st; ) {
const Edge &ed = gph[x][prv[x]],
&bk = gph[ed.to][ed.rev];
mn = min(mn, bk.cap - bk.flo); x = ed.to; }
for (int x = ls; x != st; ) {
Edge &ed = gph[x][prv[x]],
&bk = gph[ed.to][ed.rev];
bk.flo += mn; ed.flo -= mn; x = ed.to;
if (bk.ccap - bk.flo < EPS) {
v = x; } }
return mn; }
int retreat(int v) {
int ndst = n - 1;
for (const Edge &ed : gph[v]) {
if (ed.cap - ed.flo > EPS and dst[ed.to] < ndst) {
ndst = dst[ed.to]; } }
--cnt[dst[v]];
if (!cnt[dst[v]]) {
if (ndst + 1 > dst[v]) {
reach = false; } }
dst[v] = ndst + 1; ++cnt[dst[v]];
if (v != fs) {
v = gph[v][prv[v]].to; }
return v; }
type maxFlow(void) {
reach = true;
for (int i = 0; i < n; ++i) {
ptr[i] = (int) gph[i].size() - 1; }
if (exPath()) {
int v = fs;
while (dst[fs] < n) {
while (ptr[v] >= 0) {
const Edge &ed = gph[v][ptr[v]];
if (ed.cap - ed.flo > EPS and dst[ed.to] == dst[v] - 1) {
prv[ed.to] = ed.rev; v = ed.to;
if (v == ls) {
flow += augment(v); }
break; }
--ptr[v]; }
if (ptr[v] < 0) {
ptr[v] = (int) gph[v].size() - 1;
v = retreat(v);
if (!reach) {
break; } } } }
return flow; }
vector<bool> minCut(void) {
maxFlow();
vector<bool> mnc(n);
for (int i = 0; i < n; ++i) {
ans[i] = (dst[i] != n); }
return mnc; }
};
*/
template <typename type>
class DinicFlowGraph {
public:
static const type eps = (type) 0.000000001;
struct Edge {
int to, rev;
type cap, flo;
Edge() :
to(0), cap(0), flo(0), rev(0) {}
Edge(int _to, type _cap, type _flo, int _rev) :
to(_to), cap(_cap), flo(_flo), rev(_rev) {}
};
type flow;
vector<vector<Edge>> gph;
vector<int> ptr, dst, que;
int n, fs, ls;
DinicFlowGraph(int _n, int _fs, int _ls) :
n(_n), fs(_fs), ls(_ls) {
assert(0 <= min(fs, ls) and max(fs, ls) < n);
gph.resize(n); ptr.resize(n); dst.resize(n);
que.resize(n); flow = 0; }
void clearFlow(void) {
for (int i = 0; i < n; ++i) {
for (Edge &ed : gph[i]) {
ed.flo = 0; } }
flow = 0; }
void addEdge(int from, int to, type frwCap, type bkwCap) {
assert(0 <= min(from, to) and max(from, to) < n);
int fromSz = gph[from].size(), toSz = gph[to].size();
gph[from].push_back(Edge(to, frwCap, 0, toSz));
gph[to].push_back(Edge(from, bkwCap, 0, fromSz)); }
bool exPath(void) {
fill(dst.begin(), dst.end(), -1);
que[0] = ls; dst[ls] = 0;
for (int bg = 0, en = 1; bg < en; ++bg) {
int x = que[bg];
for (const Edge &ed : gph[x]) {
const Edge &bk = gph[ed.to][ed.rev];
if (bk.cap - bk.flo > eps and dst[ed.to] == -1) {
dst[ed.to] = dst[x] + 1;
if (ed.to == fs) {
return true; }
que[en++] = ed.to; } } }
return false; }
type dfs(int x, type w) {
if (x == ls) {
return w; }
int &p = ptr[x];
while (p >= 0) {
const Edge &ed = gph[x][p];
if (ed.cap - ed.flo > eps and dst[ed.to] == dst[x] - 1) {
type aux = dfs(ed.to, min(ed.cap - ed.flo, w));
if (aux > eps) {
gph[x][p].flo += aux;
gph[ed.to][ed.rev].flo -= aux;
return aux; } }
--p; }
return 0; }
type maxFlow(void) {
while (exPath()) {
for (int i = 0; i < n; ++i) {
ptr[i] = (int) gph[i].size() - 1; }
type add = 0;
while (true) {
type aux = dfs(fs, numeric_limits<type> :: max());
if (aux <= eps) {
break; }
add += aux; }
if (add <= eps) {
break; }
flow += add; }
return flow; }
vector<bool> minCut(void) {
maxFlow();
vector<int> ans(n);
for (int i = 0; i < n; ++i) {
ans[i] = (dst[i] != -1); }
return ans; }
};
int main(void) {
//#ifdef HOME
freopen("maxflow.in", "r", stdin);
freopen("maxflow.out", "w", stdout);
//#endif
int n, m; cin >> n >> m;
DinicFlowGraph<int> network(n, 0, n - 1);
for (int i = 1; i <= m; ++i) {
int x, y, c; cin >> x >> y >> c;
network.addEdge(--x, --y, c, 0); }
cout << network.maxFlow() << endl;
return 0; }