#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <string>
#include <sstream>
#include <algorithm>
#include <vector>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <random>
#include <tuple>
#include <limits>
#include <functional>
#include <complex>
#include <bitset>
#include <list>
//#include <atomic>
//#include <condition_variable>
//#include <future>
//#include <mutex>
//#include <thread>
using namespace std;
#define debug(x) cerr << #x << " = " << x << "\n"
struct MinCostFlow
{
typedef int Flow; typedef int Cost; typedef int Index;
static const Flow InfCapacity = 0x3f3f3f3f;
static const Cost InfCost = 0x3f3f3f3f;
struct Edge
{
Index to, rev;
Flow capacity;
Cost cost;
};
vector< vector<Edge> > g;
void init(int n) { g.assign(n, vector<Edge>()); }
void add(Index i, Index j, Flow capacity = InfCapacity, Cost cost = Cost())
{
Edge e, f;
e.to = j, f.to = i;
e.capacity = capacity, f.capacity = 0;
e.cost = cost, f.cost = -cost;
g[i].push_back(e), g[j].push_back(f);
g[i].back().rev = (int) g[j].size() - 1;
g[j].back().rev = (int) g[i].size() - 1;
}
void addB(Index i, Index j, Flow capacity = InfCapacity, Cost cost = Cost())
{
add(i, j, capacity, cost);
add(j, i, capacity, cost);
}
pair<Cost, Flow> min_cost_max_flow(Index s, Index t, Flow f = InfCapacity, bool useSPFA = false)
{
Index n = (Index) g.size();
pair<Cost, Flow> total = {0, 0};
vector<Cost> dist(n);
vector<Cost> potential(n);
vector<Index> prev(n);
vector<Index> prev_edge(n);
while (f > 0)
{
fill(dist.begin(), dist.end(), InfCost);
if (useSPFA || total.second == 0)
{
vector<bool> in_queue(n);
deque<Index> q;
q.push_back(s);
dist[s] = 0;
in_queue[s] = true;
while (!q.empty())
{
Index i = q.front();
q.pop_front();
in_queue[i] = false;
for (Index ei = 0; ei < (Index) g[i].size(); ei++)
{
const Edge& e = g[i][ei];
Index j = e.to;
Cost d = dist[i] + e.cost;
if (e.capacity > 0 && d < dist[j])
{
if (!in_queue[j])
{
in_queue[j] = true;
q.push_back(j);
}
dist[j] = d;
prev[j] = i;
prev_edge[j] = ei;
}
}
}
}
else
{
vector<bool> visited(n, false);
priority_queue< pair<Cost, Index> > q;
q.push({-0, s});
dist[s] = 0;
while (!q.empty())
{
Index i = q.top().second;
q.pop();
if (visited[i]) continue;
visited[i] = true;
for (Index ei = 0; ei < (Index) g[i].size(); ei++)
{
const Edge& e = g[i][ei];
if (e.capacity <= 0) continue;
Index j = e.to;
Cost d = dist[i] + (e.cost + potential[i] - potential[j]);
if (d < dist[j])
{
dist[j] = d;
prev[j] = i;
prev_edge[j] = ei;
q.push({-d, j});
}
}
}
}
if (dist[t] == InfCost) break;
if (!useSPFA) for (Index i = 0; i < n; i++) potential[i] += dist[i];
Flow d = f;
Cost dist_t = 0;
for (Index v = t; v != s; )
{
Index u = prev[v];
const Edge& e = g[u][prev_edge[v]];
d = min(d, e.capacity);
dist_t += e.cost;
v = u;
}
f -= d;
total.first += d * dist_t;
total.second += d;
for (Index v = t; v != s; )
{
Index u = prev[v];
Edge& e = g[u][prev_edge[v]];
e.capacity -= d;
g[e.to][e.rev].capacity += d;
v = u;
}
}
return total;
}
};
const int MinCostFlow::InfCost;
const int MinCostFlow::InfCapacity;
int main()
{
freopen("fmcm.in", "r", stdin);
freopen("fmcm.out", "w", stdout);
cin.sync_with_stdio(false);
int n, m, s, t;
cin >> n >> m >> s >> t;
s--, t--;
MinCostFlow mf;
mf.init(n);
for (int i = 0; i < m; i++)
{
int x, y, c, z;
cin >> x >> y >> c >> z;
x--, y--;
mf.add(x, y, c, z);
}
auto ans = mf.min_cost_max_flow(s, t);
cout << ans.first << "\n";
return 0;
}