#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <limits>
#include <algorithm>
using FlowGraph = std::vector<std::vector<int>>;
using IntTable = std::vector<std::vector<int>>;
const int NONE = -1;
std::vector<int>
bfsTree(
const FlowGraph &graph,
const IntTable &capacity,
int source,
int sink
)
{
std::vector<int> parent(graph.size(), NONE);
std::queue<int> bfsQueue;
bfsQueue.emplace(source);
while (!bfsQueue.empty()) {
auto u = bfsQueue.front();
bfsQueue.pop();
for (auto &v : graph[u])
if (v != sink && capacity[u][v] > 0 && parent[v] == NONE) {
parent[v] = u;
bfsQueue.emplace(v);
}
}
return parent;
}
int
maxFlow(
const FlowGraph &graph,
IntTable &capacity,
int source,
int sink
)
{
auto maxFlow = 0;
while (true) {
auto parentTree = bfsTree(graph, capacity, source, sink);
auto newFlow = maxFlow;
for (auto &u : graph[sink]) {
if (!capacity[u][sink] || parentTree[u] == NONE)
continue;
auto v = u;
auto w = sink;
auto min = std::numeric_limits<int>::max();
while (w != source) {
min = std::min(min, capacity[v][w]);
w = v;
v = parentTree[v];
};
newFlow += min;
v = u;
w = sink;
while (w != source) {
capacity[v][w] -= min;
capacity[w][v] += min;
w = v;
v = parentTree[v];
}
}
if (newFlow == maxFlow)
break;
else
maxFlow = newFlow;
}
return maxFlow;
}
int main()
{
std::ifstream fin{"maxflow.in"};
std::ofstream fout{"maxflow.out"};
int N, M;
fin >> N >> M;
FlowGraph graph(N);
IntTable capacity(N, std::vector<int>(N, 0));
for (auto i = 0; i < M; ++i) {
int x, y, c;
fin >> x >> y >> c;
capacity[x - 1][y - 1] = c;
graph[x - 1].emplace_back(y - 1);
graph[y - 1].emplace_back(x - 1);
}
fout << maxFlow(graph, capacity, 0, N - 1) << std::endl;
return 0;
}