#include <fstream>
#include <iostream>
#include <vector>
#include <queue>
#include <bitset>
#include <cstring>
#include <cstdio>
using namespace std;
#define pair pair<int,int>
const int NMAX = 350;
const int MMAX = 12500;
const int INF = (1<<30);
int n; int m; int source; int dest;
int cap[NMAX + 1][NMAX + 1];
int flow[NMAX + 1][NMAX + 1];
int cost[NMAX + 1][NMAX + 1];
/* res graph = cost - flow */
vector< vector<int> > g(NMAX + 1, vector<int>(0));
int before[NMAX + 1];
int oldD[NMAX + 1]; int realD[NMAX + 1];
priority_queue< pair , vector< pair > , greater< pair > > pq;
int minCost;
void read() {
scanf("%d%d%d%d", &n, &m, &source, &dest);
for(int i = 1; i <= m; ++i) {
int x; int y;
scanf("%d%d", &x, &y);
scanf("%d%d", &cap[x][y], &cost[x][y]);
cost[y][x] = -cost[x][y];
g[x].push_back(y);
g[y].push_back(x);
}
}
void bellmanFord(int sursa, int dest, vector< vector<int> >& g) {
queue<int> q;
bitset<NMAX + 1> inQueue;
for(int i = 1; i <= n; ++i)
oldD[i] = INF;
q.push(sursa);
inQueue[sursa] = true;
oldD[sursa] = 0;
while(q.empty() == false) {
int node = q.front();
q.pop();
inQueue[node] = false;
for(int x : g[node])
if(cap[node][x] && oldD[node] + cost[node][x] < oldD[x]) {
oldD[x] = oldD[node] + cost[node][x];
if(inQueue[x] == false) {
q.push(x);
inQueue[x] = true;
}
}
}
}
bool dijkstra(int start, int dest, vector< vector<int> >& g) {
vector<int> dist(NMAX + 1, INF);
/* We use this to calculate the real distance realD. We don t need this calculations. */
pq.push({0, start});
dist[start] = realD[start] = 0;
before[start] = start;
while(pq.empty() == false) {
int node = pq.top().second;
int dst = pq.top().first;
pq.pop();
if(dst > dist[node]) continue;
for(int x : g[node]) {
int maxFlow = cap[node][x] - flow[node][x];
if(maxFlow <= 0) continue;
int d = dist[node] + cost[node][x] + oldD[node] - oldD[x];
if(d >= dist[x]) continue;
dist[x] = d;
pq.push({dist[x], x});
before[x] = node;
realD[x] = realD[node] + cost[node][x];
/*Drumurile minime se schimba de la un dijkstra la altul, de aceea trebuie schimbata si
distantele cu care se calculeaza. */
}
}
return (dist[dest] != INF);
}
void solve(int start, int dest, vector< vector<int> >& g) {
/* Precalculez distantele cu BellmanFord apoi asociez muchiei x->y costul
cost[x][y] + oldD[x] - oldD[y] > 0. Drumurile minime nu se modifica. Se demonstreaza prin RA.
Distanta de la un nodul de start la un nod x este practic z1 + z2 + ... +zn - oldD[x] cu noile costuri
unde z1, z2, sunt arcele drumurilor. Trebuie demonstrat ca daca z1 + z2 + ... + zn = min
atunci z1 + z2 + ... + zn - oldD[x]= min. Evident adevarat oldD[x] este o constanta
*/
bellmanFord(start, dest, g);
/* Desi nu a fost luat in considerare si costul invers in bellmanforst, din ecuatii da si el pozitiv
cost[j][i] = -cost[i][j] + oldD[j] - oldD[i], oldD[j] > oldD[i] + cost[i][j]
Va fi luat in considerare si trebuie sa fie si el pozitiv!!
*/
while(dijkstra(start, dest, g)) {
memcpy(oldD, realD, sizeof(oldD));
/* Drumurile minime se schimba de la un dijkstra la altul, de aceea trebuie schimbata si
distantele cu care se calculeaza.
Evident se schimba pentru ca desi costurile pe muchii raman la fel, se mai taie unele muchii. */
int x = dest; int maxFlow = INF;
while(before[x] != x) {
maxFlow = min(maxFlow, cap[before[x]][x] - flow[before[x]][x]);
x = before[x];
}
x = dest;
minCost += maxFlow * realD[dest];
while(before[x] != x) {
flow[before[x]][x] += maxFlow;
flow[x][before[x]] -= maxFlow;
x = before[x];
}
}
}
int main() {
freopen("fmcm.in", "r", stdin);
freopen("fmcm.out", "w", stdout);
read();
/*Practic se cauta taietura minima
the max-flow min-cut theorem states that in a flow network, the maximum amount of flow
passing from the source to the sink is equal to the minimum capacity that,
when removed in a specific way from the network, causes the situation that
no flow can pass from the source to the sink.
*/
// Se taie muchii (si se adauga altele, inversele) pana cand nu mai poti accesa dest din sursa
// Complexitate: Dijkstra O(MlogN) => O(N * M^ 2 * logN), adica trebuie sa repet de N*M
//idee de demonstratie a de ce trebuie sa repet de atatea ori: dupa M repetari drumul scade cu un nod.
solve(source, dest, g);
printf("%d", minCost);
return 0;
}