#include<fstream>
#include<iostream>
#include<vector>
#include<cstring>
#include<unordered_map>
#include<algorithm>
#include<utility>
using namespace std;
struct node {
int x, c, idx;
node* rev;
};
int n,m,k,f,q[50000];
node* p[50000];
vector<node> g[50000];
bool viz[50000];
bool flow(int s, int d) {
memset(viz,0,sizeof(viz));
int l = 1, r = 1;
q[1] = s; p[s] = nullptr;
bool ok = 0;
while (l<=r) {
int nodc = q[l++];
for (int i=0; i<g[nodc].size(); ++i)
if (!viz[g[nodc][i].x] && g[nodc][i].c > 0) {
if (g[nodc][i].x != d) {
viz[g[nodc][i].x] = 1;
p[g[nodc][i].x] = &g[nodc][i];
q[++r] = g[nodc][i].x;
} else {
int minc = g[nodc][i].c;
int aux = nodc;
while (p[aux] != nullptr) {
minc = min(minc, p[aux]->c);
aux = p[aux]->idx;
}
f += minc;
aux = nodc;
while (p[aux] != nullptr) {
p[aux]->c -= minc;
p[aux]->rev->c += minc;
aux = p[aux]->idx;
}
ok = 1;
}
}
}
return ok;
}
void addEdge(int x, int y, int cap) {
g[x].push_back({.x = y, .c = cap, .idx = x, .rev = nullptr});
g[y].push_back({.x = x, .c = 0, .idx = y, .rev = nullptr});
g[x][g[x].size()-1].rev = &g[y][g[y].size()-1];
g[y][g[y].size()-1].rev = &g[x][g[x].size()-1];
}
int main(){
//ifstream cin("/usr/local/google/home/catavlas/ClionProjects/cf_training/subsecvente.in");
ifstream cin("maxflow.in");
ofstream cout("maxflow.out");
cin>>n>>m;
for (int i=1; i<=m; ++i) {
int x, y, z;
cin>>x>>y>>z;
addEdge(x,y,z);
}
while (flow(1, n)) {}
cout<<f;
return 0;
}