// #include <bits/stdc++.h>
#include <iostream>
// #include <limits.h>
#include <cstring>
#include <queue>
using namespace std;
#define V 100
// int M[100][100];
int R[100][100];
bool bfs(int R[V][V], int s, int t, int parent[]) {
queue<int> q;
vector<bool> vis(V);
q.push(s);
parent[s] = -1;
while(!q.empty()) {
int u = q.front();
q.pop();
// aceck around
vis[u] = true;
for (int v=0; v< (t + 1); v++)
{
//std::cout << vis[v] << " " << u << " " << v << " " << R[u][v] << std::endl;
if (vis[v] == false && R[u][v] > 0)
{
q.push(v);
parent[v] = u;
//std::cout << v << " " << u << std::endl;
}
}
}
//cout << "visited " << vis[t] << endl;
return (vis[t] == true);
}
// Returns the maximum flow from s to t in the given graph
int max_flow(int R[V][V], int s, int t)
{
int u, v;
int parent[V]; // This array is filled by BFS and to store path
int max_flow = 0; // There is no flow initially
// Augment the flow while tere is path from source to sink
while (bfs(R, s, t, parent))
{
// Find minimum residual capacity of the edges along the
// path filled by BFS. Or we can say find the maximum flow
// through the path found.
int path_flow = INT_MAX;
for (v=t; v!=s; v=parent[v])
{
u = parent[v];
path_flow = min(path_flow, R[u][v]);
//cout << path_flow << endl;
}
for (v=t; v != s; v=parent[v])
{
u = parent[v];
R[u][v] -= path_flow;
R[v][u] += path_flow;
}
// Add path flow to overall flow
max_flow += path_flow;
}
// Return the overall flow
return max_flow;
}
int main() {
int n, m;
cin >> n >> m;
// memset(M, 0, sizeof(int) * 100 * 100);
memset(R, 0, sizeof(int) * 100 * 100);
for (int i=0; i<m; i++) {
int a, b, w;
cin >> a >> b >> w;
// M[a-1][b-1] = w;
R[a-1][b-1] = w;
}
cout << max_flow(R, 0, n - 1);
}