#include<bits/stdc++.h>
#define all(x) x.begin(), x.end()
#define sz(x) (int)x.size()
#define trav(i, x) for (auto i : x)
#define re(x, y, z) for (int x=y; x<z; ++x)
#define eb emplace_back
#define set_to(x, v) fill(all(x), v)
using namespace std;
using ll = long long;
using vi = vector<int>;
const int inf = 1e9;
struct Dinic {
struct Edge {
int to, cap, flow, link;
Edge() {}
Edge(int to, int cap, int link, int flow=0):
to(to), cap(cap), link(link), flow(flow) {}
};
vector<vector<Edge>> g;
vi d, pt;
Dinic(int n): g(n), d(n), pt(n) {}
void addEdge(int a, int b, int cap) {
if (a == b) return;
int pa = sz(g[a]), pb = sz(g[b]);
g[a].eb(b, cap, pb); g[b].eb(a, 0, pa);
}
bool bfs(int src, int snk) {
queue<int> q({src});
set_to(d, inf);
d[src] = 0;
while (!q.empty()) {
int v = q.front(); q.pop();
if (v == snk) return true;
trav(e, g[v]) {
if (e.flow >= e.cap) continue;
if (d[e.to] > d[v] + 1) {
d[e.to] = d[v] + 1;
q.emplace(e.to);
}
}
}
return false;
}
int dfs(int x, int snk, int flow=inf) {
if (x == snk || !flow) return flow;
for (; pt[x] < sz(g[x]); ++pt[x]) {
auto& e = g[x][pt[x]];
if (d[e.to] == d[x] + 1) {
int res = min(e.cap - e.flow, flow);
if (int push = dfs(e.to, snk, res)) {
e.flow += push;
g[e.to][e.link].flow -= push;
return push;
}
}
}
return 0;
}
ll solve(int s, int t) {
ll res = 0;
while (bfs(s, t)) {
set_to(pt, 0);
while (int flow = dfs(s, t)) {
res += flow;
}
}
return res;
}
};
void setIO(string name) {
string input = name + ".in";
string output = name + ".out";
freopen(input.c_str(), "r", stdin);
freopen(output.c_str(), "w", stdout);
}
int main() {
setIO("maxflow");
int n, m;
scanf("%d %d", &n, &m);
Dinic D(n);
for(int i = 0; i < m; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
u--; v--;
D.addEdge(u, v, w);
}
printf("%lld\n", D.solve(0, n - 1));
return 0;
}