#pragma GCC optimize(3)
#include <bits/stdc++.h>

using namespace std;

const int MAXN = 1205;
template <int MAXN, class T = int> struct HLPP {
    const T INF = numeric_limits<T>::max();
    struct edge {
        int to, rev;
        T f;
    };
    int s = MAXN - 1, t = MAXN - 2;
    vector<edge> edges[MAXN];
    vector<int> lst[MAXN], gap[MAXN];
    T excess[MAXN];
    int highest, height[MAXN], cnt[MAXN];
    void addEdge(int from, int to, int f, bool isDirected = true) {
        edges[from].push_back({to, (int)edges[to].size(), f});
        edges[to].push_back({from, (int)edges[from].size() - 1, isDirected ? 0 : f});
    }
    void updHeight(int v, int nh) {
        if (height[v] != MAXN)
            cnt[height[v]]--;
        height[v] = nh;
        if (nh == MAXN)
            return;
        cnt[nh]++, highest = nh;
        gap[nh].push_back(v);
        if (excess[v] > 0) {
            gap[nh].push_back(v);
            lst[nh].push_back(v);
        }
    }
    void globalRelabel() {
        fill(begin(height), end(height), MAXN);
        fill(begin(cnt), end(cnt), 0);
        for (int i = 0; i < MAXN; i++) {
            lst[i].clear();
            gap[i].clear();
        }
        height[t] = 0;
        queue<int> q({t});
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            for (auto &e : edges[v]) {
                if (height[e.to] != MAXN || edges[e.to][e.rev].f <= 0)
                    continue;
                updHeight(e.to, height[v] + 1);
                q.push(e.to);
            }
            highest = height[v];
        }
    }
    void push(int v, edge &e) {
        if (excess[e.to] == 0)
            lst[height[e.to]].push_back(e.to);
        T df = min(excess[v], e.f);
        e.f -= df, edges[e.to][e.rev].f += df;
        excess[v] -= df, excess[e.to] += df;
    }
    int work = 0;
    void discharge(int v) {
        int nh = MAXN;
        for (auto &e : edges[v]) {
            if (e.f <= 0)
                continue;
            if (height[v] == height[e.to] + 1) {
                push(v, e);
                if (excess[v] <= 0)
                    return;
            } else
                nh = min(nh, height[e.to] + 1);
        }
        work++;
        if (cnt[height[v]] > 1)
            updHeight(v, nh);
        else {
            for (int i = height[v]; i <= highest; i++) {
                for (auto j : gap[i])
                    updHeight(j, MAXN);
                gap[i].clear();
            }
        }
    }
    T calc(int n) {
        fill(begin(excess), end(excess), 0);
        excess[s] = INF, excess[t] = -INF;
        globalRelabel();
        for (auto &e : edges[s])
            push(s, e);
        for (; highest >= 0; highest--) {
            while (!lst[highest].empty()) {
                int v = lst[highest].back();
                lst[highest].pop_back();
                discharge(v);
                if (work > 4 * n) {
                    globalRelabel();
                    work = 0;
                }
            }
        }
        return excess[t] + INF;
    }
};

HLPP<MAXN, long long> hlpp;

inline void scan_int(int *p) {
    static char c;
    while ((c = getchar_unlocked()) < '0')
        ; // just to be safe
    for (*p = c - '0'; (c = getchar_unlocked()) >= '0'; *p = *p * 10 + c - '0')
        ;
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n, m;
    scan_int(&n), scan_int(&m);
    // cin >> n >> m;
    int s = 1, t = n;
    scan_int(&s), scan_int(&t);
    // cin >> s >> t;
    for (int i = 0, u, v, f; i < m; ++i) {
        scan_int(&u), scan_int(&v), scan_int(&f);
        // cin >> u >> v >> f;
        hlpp.addEdge(u, v, f, true);
    }
    hlpp.s = s, hlpp.t = t;
    cout << hlpp.calc(n) << endl;
}
