#include <bits/stdc++.h>
#define maxN 352
#define c1 0x3f
#define inf 0x3f3f3f3f
#define pii pair < int, int >
using namespace std;
FILE *fin = freopen("fmcm.in", "r", stdin);
FILE *fout = freopen("fmcm.out", "w", stdout);
int n, m, S, D;
int r[maxN][maxN], cost[maxN][maxN];
int old_d[maxN], d[maxN], real_d[maxN], prv[maxN];
vector < int > G[maxN];
priority_queue< pii, vector< pii >, greater< pii > > H;
queue < int > Q;
bool inQ[maxN];
int Flow, FlowCost;
void AddEdge(int u, int v, int cap, int cst)
{
r[u][v] = cap;
cost[u][v] = cst;
cost[v][u] = -cst;
G[u].push_back(v);
G[v].push_back(u);
}
inline bool Dijkstra()
{
memset(d, c1, sizeof(d));
d[S] = real_d[S] = 0;
H.push(pii{d[S], S});
while (!H.empty())
{
pii x = H.top();
H.pop();
int nod = x.second;
if (d[nod] != x.first)
continue;
for (int adj : G[nod])
if (r[nod][adj])
{
int newD = d[nod] + cost[nod][adj] + old_d[nod] - old_d[adj];
if (newD < d[adj])
{
d[adj] = newD;
real_d[adj] = real_d[nod] + cost[nod][adj];
H.push(pii{newD, adj});
prv[adj] = nod;
}
}
}
memcpy(old_d, real_d, sizeof(real_d));
if (d[D] == inf)
return false;
int Min = inf, crtCost = 0, nod = D;
while (nod != S)
{
crtCost += cost[prv[nod]][nod];
Min = min(Min, r[prv[nod]][nod]);
nod = prv[nod];
}
nod = D;
while (nod != S)
{
r[prv[nod]][nod] -= Min;
r[nod][prv[nod]] += Min;
nod = prv[nod];
}
Flow += Min;
FlowCost += Min * real_d[D];
return true;
}
inline bool BellmanFord()
{
memset(old_d, c1, sizeof(old_d));
inQ[S] = 1;
Q.push(S);
while (!Q.empty())
{
int nod = Q.front();
Q.pop();
inQ[nod] = 0;
for (int adj : G[nod])
if (r[nod][adj] && old_d[nod] + cost[nod][adj] < old_d[adj])
{
old_d[adj] = old_d[nod] + cost[nod][adj];
if (!inQ[adj])
{
inQ[adj] = 1;
Q.push(adj);
}
}
}
return (old_d[D] != inf);
}
int main()
{
scanf("%d%d%d%d", &n, &m, &S, &D);
while (m --)
{
int x, y, cap, cst;
scanf("%d%d%d%d", &x, &y, &cap, &cst);
AddEdge(x, y, cap, cst);
}
Flow = 0;
FlowCost = 0;
BellmanFord();
for (; Dijkstra(); );
printf("%d\n", FlowCost);
return 0;
}