#include "bits/stdc++.h"
using namespace std;

//?????????
#pragma region MACRO 
#define putans(x)  std::cerr << "[ answer ]: " ; cout << (x) << endl
#define dputans(x) std::cerr << "[ answer ]: "; cout << setprecision(27) << (double)(x) << endl
#define REP(i,a,n) for(int i=(a); i<(int)(n); i++)
#define RREP(i,a,n) for(int i=(int)(n-1); i>= a; i--)
#define rep(i,n) REP(i,0,n)
#define rrep(i,n) RREP(i,0,n)
#define all(a) begin((a)),end((a))
#define mp make_pair
#define exist(container, n) ((container).find((n)) != (container).end())
#define equals(a,b) (fabs((a)-(b)) < EPS)
#ifdef _DEBUG //???????????????????????????????????????????????????
std::ifstream ifs("data.txt");
#define put ifs >>
#else //?????£????????????????????§?????????????????????
#define put cin >>
#endif
#pragma endregion
//???????????°??????????????´
#pragma region CODING_SUPPORT
#ifdef _DEBUG
#define dbg(var0) { std::cerr << ( #var0 ) << "=" << ( var0 ) << endl; }
#define dbg2(var0, var1) { std::cerr << ( #var0 ) << "=" << ( var0 ) << ", "; dbg(var1); }
#define dbg3(var0, var1, var2) { std::cerr << ( #var0 ) << "=" << ( var0 ) << ", "; dbg2(var1, var2); }
#define dbgArray(a,n) {std::cerr << (#a) << "=";  rep(i,n){std::cerr <<(a[i])<<",";} cerr<<endl;} 
#else
#define dbg(var0) {}
#define dbg2(var0, var1) {}
#define dbg3(var0, var1, var2) {}
#define dbgArray(a,n) {}
#endif 
#pragma endregion 
//typedef????????????????????????????¶????????????§?????????
#pragma region TYPE_DEF
typedef long long ll;
typedef pair<int, int> pii; typedef pair<string, string> pss; typedef pair<int, string>pis;
typedef vector<string> vs; typedef vector<int> vi;
#pragma endregion
//??????????????°(???????????????????????§??????)
#pragma region CONST_VAL
#define PI (2*acos(0.0))
#define EPS (1e-10)
#define MOD (ll)(1e9 + 7)
#define INF (ll)(2*1e9)
#pragma endregion

struct edge { int to, cap, rev; };

static const int MAX_V = 10000;
int V;
vector<edge> G[MAX_V];
int level[MAX_V];
int iter[MAX_V];

void addEdge(int from, int to, int cap) {
	G[from].push_back(( edge{ to, cap, (int)G[to].size() } ));
	G[to].push_back(( edge{ from, 0, (int)G[from].size() - 1 } ));
}

void dinicBFS(int s) {
	fill(level, level + V, -1);
	queue<int> que;
	level[s] = 0;
	que.push(s);
	while (!que.empty()) {
		int v = que.front(); que.pop();
		rep(i, G[v].size()) {
			edge &e = G[v][i];
			if (e.cap > 0 && level[e.to] <0 ) {
				level[e.to] = level[v] + 1;
				que.push(e.to);
			}
		}
	}
}

int dinicDFS(int v, int t,int f) {
	if (v == t) return f;
	for (int &i = iter[v]; i < G[v].size(); i++) {
		edge &e = G[v][i];
		if (e.cap > 0 && level[v] < level[e.to]) {
			int d = dinicDFS(e.to, t, min(f,e.cap));
			if (d > 0) {
				e.cap -= d;
				G[e.to][e.rev].cap += d;
				return d;
			}
		}
	}
	return 0;
}

int maxFlowDinic(int s, int t){
	int flow = 0;
	for (;;) {
		dinicBFS(s);
		if (level[t] < 0) return flow;
		fill(iter, iter + V, 0);
		int f;
		while (( f = dinicDFS(s, t, INF) ) > 0) {
			flow += f;
		}
	}
}

int main() {
	int v, e; put v >> e;
	V = v;
	rep(i, e) {
		int u, v, c; put u >> v >> c;
		addEdge(u, v, c);
	}
	cout << maxFlowDinic(0 , v-1) << endl;

END:
	return 0;
}



//static const int n = 100;
//int d[n][n];

/*
void topologicalSort() {
	auto bfs = [&](int s)->void {
		queue<int> q;
		q.push(s);
		V[s] = true;
		while (!q.empty()) {
			int u = q.front(); q.pop();
			rep(i, G[u].size()) {
				int v = G[u][i];
				indeg[v]--;
				if (indeg[v] == 0 && !V[v]) {
					q.push();
				}
			}
		}
	}
}
rep(i, n) {
	indeg[i] = 0;
}
rep(u, n) {
	rep(i, G[u].size()) {
		int v = G[u][i];
		indeg[v]++;
	}
	rep(i, n) {
		if (indeg[i] == !V[i]) bfs(u);
	}//????????§???????????????
}
}*/

Measured memory_bytes: 3424