#include <bits/stdc++.h>
std::ifstream in("maxflow.in");
std::ofstream out("maxflow.out");
const int DIM = 105;
// unverified
template <class type>
class MaxFlow {
private:
static constexpr type INF = std::numeric_limits<type> :: max() / 2;
static constexpr long double EPS = 1e-6;
static inline int cmp(const type x) {
if (fabs(x) < EPS)
return 0;
return x < 0 ? -1 : 1;
}
struct edge {
int x, y; type flo, cap;
edge(int _x, int _y, type _cap) :
x(_x), y(_y), cap(_cap), flo(0) {};
};
std::vector<bool> oki; std::deque<int> que;
std::vector<edge> lst; std::vector<type> dis;
std::vector<int> ptx; std::vector<std::vector<int>> edg;
bool bfs(const int src, const int dst) {
std::fill(dis.begin(), dis.end(), (type)INF); dis[src] = 0;
for (que.assign(1, src); que.size() and dis[dst] == INF; que.pop_front()) {
int x = que.front();
if (x == dst) continue;
for (int it : edg[x]) {
int y = lst[it].y;
if (cmp(lst[it].cap - lst[it].flo) and dis[y] > dis[x] + 1)
dis[y] = dis[x] + 1, que.push_back(y);
}
}
return dis[dst] != INF;
}
type dfs(const int x, const int dst, type cap) {
if (x == dst) return cap;
type flo = 0;
for (; ptx[x] < edg[x].size() and cmp(cap - flo); ++ptx[x]) {
int it = edg[x][ptx[x]], y = lst[it].y;
if (cmp(dis[y] - dis[x] - 1))
continue;
if (!cmp(lst[it].cap - lst[it].flo))
continue;
type aux = dfs(y, dst, std::min(cap - flo, lst[it].cap - lst[it].flo));
if (aux)
lst[it].flo += aux, lst[it ^ 1].flo -= aux, flo += aux;
}
return flo;
}
void fill(const int x, std::vector<int> &ans) {
oki[x] = true;
for (int it : edg[x]) {
int y = lst[it].y;
if (cmp(lst[it].cap - lst[it].flo) and !oki[y])
fill(y, ans);
}
}
public:
MaxFlow(int sz) {
edg.resize(sz); dis.resize(sz);
oki.resize(sz); ptx.resize(sz);
}
inline void addUndirectedEdge(const int x, const int y, const type c) {
edg[x].push_back((int) lst.size()); lst.push_back(edge(x, y, c));
edg[y].push_back((int) lst.size()); lst.push_back(edge(y, x, c));
}
inline void addDirectedEdge(const int x, const int y, const type c) {
edg[x].push_back((int) lst.size()); lst.push_back(edge(x, y, c));
edg[y].push_back((int) lst.size()); lst.push_back(edge(y, x, 0));
}
type getMaxFlow(const int src, const int dst) {
for (int i = 0; i < lst.size(); ++i)
lst[i].flo = 0;
type ans = 0, aux;
while (bfs(src, dst)) {
std::fill(ptx.begin(), ptx.end(), 0);
while (cmp(aux = dfs(src, dst, INF)))
ans += aux;
}
return ans;
}
type getMinCut(const int src, const int dst, std::vector<int> &ans) {
std::fill(oki.begin(), oki.end(), false);
type sol = getMaxFlow(src, dst);
fill(src, ans); ans.clear();
for (int i = 0; i < edg.size(); ++i)
if (oki[i]) ans.push_back(i);
return sol;
}
};
int main(void) {
int n, m;
in >> n >> m;
MaxFlow<int> myNetwork(n + 1);
for (int i = 1; i <= m; ++i) {
int x, y, c;
in >> x >> y >> c;
myNetwork.addDirectedEdge(x, y, c);
}
out << myNetwork.getMaxFlow(1, n);
return 0;
}