最大流 = 最小割
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m(x) memset(x, 0, sizeof(x))
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 10;
ll inf = ll(1) << 29;
struct MF
{
const static int maxn = 1e6 + 10;
ll n, m, s, t, maxflow;
ll head[maxn], ver[maxn << 1], edge[maxn << 1], Next[maxn << 1], d[maxn], tot;
void init()
{
tot = 1;
memset(head, 0, sizeof(head));
}
void add(ll x, ll y, ll z)
{
ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
ver[++tot] = x, edge[tot] = 0, Next[tot] = head[y], head[y] = tot;
}
bool bfs()
{
memset(d, 0, sizeof(d));
queue <int> q;
q.push(s); d[s] = 1;
while(!q.empty())
{
int x = q.front(); q.pop();
for(int i = head[x]; i; i = Next[i])
{
if(edge[i] && !d[ver[i]])
{
q.push(ver[i]);
d[ver[i]] = d[x] + 1;
if(ver[i] == t)
return true;
}
}
}
return false;
}
ll dinic(ll x, ll flow)
{
if(x == t) return flow;
ll rest = flow, k;
for(ll i = head[x]; i && rest; i = Next[i])
{
if(edge[i] && d[ver[i]] == d[x] + 1)
{
k = dinic(ver[i], min(rest, edge[i]));
if(!k) d[ver[i]] = 0;
edge[i] -= k;
edge[i ^ 1] += k;
rest -= k;
}
}
return flow - rest;
}
ll cal()
{
ll flow = 0, maxflow = 0;
while(bfs())
while(flow = dinic(s, inf)) maxflow += flow;
return maxflow;
}
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
MF M;
M.init();
cin >> M.n >> M.m >> M.s >> M.t;
ll a, b, c;
for(int i = 0; i < M.m; ++i)
{
cin >> a >> b >> c;
M.add(a, b, c);
}
cout << M.cal() << '\n';
return 0;
}