#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <list>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <random>
#include <complex>
#include <assert.h>

using namespace std;
typedef long long ll;
#define endl '\n'

template<typename T>
inline bool chmin(T& x, T a) {
	if (x >= a) { x = a; return true; }
	return false;
}

template<typename T>
inline bool chmax(T& x, T a) {
	if (x <= a) { x = a; return true; }
	return false;
}

class flowClass {
public:
	flowClass() {
		N = 0;
		M = 0;
	}
	flowClass(int _N) {
		N = 0;
		M = 0;
		for (int i = 0; i < _N; i++) {
			addNode(i);
		}
	}

	void addNode(int n) {
		assert(mp.find(n) == mp.end());
		mp.insert({ n, N });
		N++;
		next.resize(N);
		back.resize(N);
	}
	void addEdge(int from, int to, ll data = 0) {
		assert(mp.find(from) != mp.end());
		assert(mp.find(to) != mp.end());
		from = mp[from]; to = mp[to];

		edgeData.push_back({ { from, to }, data });
		next[from].push_back({ to, M });
		back[to].push_back({ from, M });
		M++;
	}

	struct edgeClass
	{
		edgeClass(int _to, ll _capacity, int _rev_i) {
			to = _to; capacity = _capacity; rev_i = _rev_i;
		}
		int to; ll capacity; int rev_i;
	};
	ll Ford_Fulkerson_dfs(int s, int t, ll flow, vector<vector<edgeClass>> &edge, vector<int> &step) {
		if (s == t) {
			return flow;
		}
		for (int i = 0; i < edge[s].size(); i++) {
			int s2 = edge[s][i].to;
			if (step[s2] == -1 && edge[s][i].capacity > 0) {
				step[s2] = step[s] + 1;
				ll result = Ford_Fulkerson_dfs(s2, t, min(flow, edge[s][i].capacity), edge, step);
				if (result > 0) {
					edge[s][i].capacity -= result;
					edge[s2][edge[s][i].rev_i].capacity += result;
					return result;
				}
			}
		}
		return 0;
	}
	ll Ford_Fulkerson(int from, int to, vector<pair<int, ll>> result) { // O(E * maxFlow)
		assert(mp.find(from) != mp.end());
		assert(mp.find(to) != mp.end());
		from = mp[from]; to = mp[to];

		vector<vector<edgeClass>> edge(N);
		for (int n1 = 0; n1 < N; n1++) {
			for (auto itr = next[n1].begin(); itr != next[n1].end(); itr++) {
				int n2 = itr->first;
				edge[n1].push_back(edgeClass(n2, edgeData[itr->second].second, edge[n2].size()));
				edge[n2].push_back(edgeClass(n1, 0, edge[n1].size() - 1));
			}
		}

		ll ans = 0;

		ll flow_max1 = 0, flow_max2 = 0;
		for (int i = 0; i < next[from].size(); i++) {
			flow_max1 += edgeData[next[from][i].second].second;
		}
		for (int i = 0; i < back[to].size(); i++) {
			flow_max2 += edgeData[back[to][i].second].second;
		}
		ll flow_max = min(flow_max1, flow_max2);

		while (1) {
			vector<int> step(N, -1);
			step[from] = 0;
			ll flow = Ford_Fulkerson_dfs(from, to, flow_max, edge, step);
			ans += flow;
			if (flow == 0) {
				break;
			}
		}

		return ans;
	}

	ll Ford_Fulkerson(int from, int to) {
		vector<pair<int, ll>> v;
		return Ford_Fulkerson(from, to, v);
	}

	int N, M;
	unordered_map<int, int> mp; // ノード番号
	vector<pair<pair<int, int>, ll>> edgeData; // 始点と終点と保持するデータ
	vector<vector<pair<int, int>>> next; // 行き先とエッジ番号
	vector<vector<pair<int, int>>> back; // 戻る先とエッジ番号

	// Ford-Fulkerson法
	vector<ll> capacity_in, capacity_out; // その頂点を出入りする
};

int main() {
	ios::sync_with_stdio(false);
	std::cin.tie(0);

	int V, E; cin >> V >> E;
	flowClass F(V);
	for (int i = 0; i < E; i++) {
		int a, b, c; cin >> a >> b >> c;
		F.addEdge(a, b, c);
	}

	cout << F.Ford_Fulkerson(0, V - 1) << endl;

	return 0;
}


Measured memory_bytes: 3304