#include <fstream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
ifstream fin("maxflow.in");
ofstream fout("maxflow.out");
const int N = 1001;
const int inf = 9999999;
int n, m;
int lv[N], q[N], poz[N];
struct edge
{
int to, rev, cap;
};
vector<edge> v[N];
//builds the level graph
int bfs(int s, int d)
{
int bott = 0;
int top = 1;
q[bott] = s;
lv[s] = 0;
while(bott < top)
{
s = q[bott++];
for(int i=0; i<v[s].size(); i++)
{
edge node = v[s][i];
if(lv[node.to] == -1 && node.cap > 0)
{
lv[node.to] = lv[s] + 1;
q[top++] = node.to;
}
}
}
return lv[d] != -1;
}
int dfs(int s, int d, int flow)
{
//if we reached d, we can push some flow
if(s == d)
return flow;
for(int i=poz[s]; i<v[s].size(); i++)
{
edge node = v[s][i];
//we only push on the level graph
if(lv[node.to] == lv[s] + 1 && node.cap > 0)
{
int new_flow = min(flow, node.cap);
new_flow = dfs(node.to, d, new_flow);
//if we can push flow, we do it
if(new_flow > 0)
{
v[s][i].cap -= new_flow;
//track the pushed flow
v[node.to][node.rev].cap += new_flow;
return new_flow;
}
}
//this section was fully explored we don't need to do it again on this level graph
poz[s]++;
}
return 0;
}
int dinic(int s, int d)
{
int max_flow = 0;
int ok = 1;
//if there is still a path from s to d
while(ok)
{
//level graph in bfs order
memset(lv, -1, N *sizeof(int));
//optimization to ignore already searched paths in dfs
memset(poz, 0, N *sizeof(int));
ok = bfs(s, d);
if(ok)
{
int flow = 0;
//while we can push flow we do it
do
{
//just a straight push from s to d, thee graph is explored only in depth
flow = dfs(s, d, inf);
max_flow += flow;
} while (flow > 0);
}
}
return max_flow;
}
int main()
{
fin >> n >> m;
int x, y, c;
for(int i=0; i<m; i++)
{
//we need to add a reverse edge to track the pushed flow and reroute it if necessary
fin >> x >> y >> c;
v[x].push_back({y, (int)v[y].size(), c});
v[y].push_back({x, (int)v[x].size() - 1, 0});
}
fout << dinic(1, n);
return 0;
}