#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstring>
const int maxn = 1214;
const long long INF = 1e10;
struct edge {
int to;
int cap;
size_t rev;
};
int cur[maxn];
int level[maxn];
bool isedge[maxn][maxn];
std::vector <edge> G[maxn];
void add_edge(int x, int y, int cap) {
if (isedge[x][y]) {
G[x][isedge[x][y]].cap += cap;
}
else {
G[x].push_back(edge{ y,cap,G[y].size() });
G[y].push_back(edge{ x,0,G[x].size() - 1 });
isedge[x][y] = G[x].size()-1;
}
}
void find_level(int s,int t) {
std::queue <int> q;
q.push(s);
memset(level, -1, sizeof(level));
level[s] = 0;
while (!q.empty()) {
int head = q.front();
q.pop();
for (int i = 0; i < G[head].size(); ++i) {
if (level[G[head][i].to] == -1 && G[head][i].cap > 0) {
level[G[head][i].to] = level[head] + 1;
q.push(G[head][i].to);
}
}
}
}
int dfs(int s,int t,int f) {
if (s == t)return f;
for (int& i = cur[s]; i < G[s].size(); ++i) {
edge& e = G[s][i];
if (level[e.to] > level[s] && e.cap > 0) {
int temp = dfs(e.to, t, std::min(f, e.cap));
if (temp > 0) {
e.cap -= temp;
G[e.to][e.rev].cap += temp;
return temp;
}
}
}
return 0;
}
int max_flow(int s, int t) {
int maxflow = 0;
while (1) {
find_level(s, t);
if (level[t] == -1)return maxflow;
memset(cur, 0, sizeof(cur));
while (1) {
int flow = dfs(s, t, INF);
if (flow == 0)break;
else maxflow += flow;
}
}
}
int main() {
int n, m,s,t;
while (std::cin >> n >> m>>s>>t) {
memset(isedge, 0, sizeof(isedge));
for (int i = 1; i <= n; ++i) {
G[i].clear();
}
for (int i = 1; i <= m; ++i) {
int x, y, z;
std::cin >> x >> y >> z;
add_edge(x, y, z);
}
std::cout << max_flow(s, t)<<std::endl;
}
return 0;
}