#include <bits/stdc++.h>
using namespace std;
#define debug(x) cerr << #x << " = " << x << "\n"
#define all(x) (x).begin(),(x).end()
#define len(x) (x).length()
#define sqr(x) (x) * (x)
using ull = unsigned long long;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
template <typename T>
ostream& operator<<(ostream &os, const vector<T> &v) { os << '{'; string sep; for (const auto &x : v) os << sep << x, sep = ", "; return os << '}'; }
template <typename A, typename B>
ostream& operator<<(ostream &os, const pair<A, B> &p) { return os << '(' << p.first << ", " << p.second << ')'; }
const int INF = INT_MAX;
const int MOD = 1e9 + 7;
const double EPS = 1e-9;
const double PI = acos(-1);
ll t, n;
struct Graph {
vector<vector<ll>> adj, capacity, cost;
vector<ll> parent, dist, new_dist, d;
ll FlowCost = 0, Flow = 0;
Graph(int n = -1) {
init(n);
}
void init(int n) {
adj.resize(n + 1);
capacity.resize(n + 1, vector<ll>(n + 1, 0));
cost.resize(n + 1, vector<ll>(n + 1, 0));
parent.resize(n + 1);
dist.resize(n + 1, INF);
new_dist.resize(n + 1, 0);
d.resize(n + 1, INF);
}
void addEdge(ll u, ll v, ll cap, ll _cost) {
adj[u].push_back(v);
adj[v].push_back(u);
capacity[u][v] = cap;
cost[u][v] = _cost;
cost[v][u] = -_cost;
}
void bellmanFord(ll s) {
queue<ll> q;
vector<bool> inQueue(n + 1, false);
q.push(s);
inQueue[s] = true;
dist[s] = 0;
while (not q.empty()) {
ll cur = q.front();
q.pop();
inQueue[cur] = false;
for (auto next: adj[cur]) {
if (capacity[cur][next] and dist[cur] + cost[cur][next] < dist[next]) {
dist[next] = dist[cur] + cost[cur][next];
if (not inQueue[next]) {
q.push(next);
inQueue[next] = true;
}
}
}
}
}
bool dijkstra(ll s, ll t) {
priority_queue<pll, vector<pll>, greater<pll>> pq;
pq.push({0, s});
fill(all(d), INF);
d[s] = 0, new_dist[s] = 0;
while (not pq.empty()) {
ll cur_cost = pq.top().first, cur = pq.top().second;
pq.pop();
if (d[cur] != cur_cost) continue;
for (auto next: adj[cur]) {
if (capacity[cur][next]) {
ll new_d = d[cur] + cost[cur][next] + dist[cur] - dist[next];
if (new_d < d[next]) {
d[next] = new_d;
new_dist[next] = new_dist[cur] + cost[cur][next];
parent[next] = cur;
pq.push({d[next], next});
}
}
}
}
dist.assign(all(new_dist));
if (d[t] == INF) return false;
ll newFlow = INF, newCost = 0, cur = t;
while (cur != s) {
newFlow = min(newFlow, capacity[parent[cur]][cur]);
newCost += cost[parent[cur]][cur];
cur = parent[cur];
}
cur = t;
while (cur != s) {
capacity[parent[cur]][cur] -= newFlow;
capacity[cur][parent[cur]] += newFlow;
cur = parent[cur];
}
Flow += newFlow;
FlowCost += newFlow * newCost;
return true;
}
ll flow(ll s, ll t) {
bellmanFord(s);
while(dijkstra(s, t));
return FlowCost;
}
};
int main(){
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
/// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
ifstream cin("fmcm.in");
ofstream cout("fmcm.out");
ll m, s, t, u, v, cap, cost;
cin >> n >> m >> s >> t;
Graph g(n);
for (int i = 1; i <= m; i++) {
cin >> u >> v >> cap >> cost;
g.addEdge(u, v, cap, cost);
}
cout << g.flow(s, t);
return 0;
}