#include <iostream>
#include <vector>
#include <queue>
#define MAXN 350
#define MAXDIST 10000
#define INF 1000000000
using namespace std;
struct node{
bool visited, isInQ;
int parent;
vector <int> neighbours;
};
struct edgePq{
int cost, b;
};
int cost[MAXN][MAXN];
int cap[MAXN][MAXN];
int dist[MAXN];
node graph[MAXN];
queue <int> q;
priority_queue <edgePq> pq;
int virtualDist[MAXN];
int realDist[MAXN];
bool operator<(edgePq a, edgePq b) {
return a.cost > b.cost;
}
void addEdge(int a, int b, int costs, int capacity) {
graph[a].neighbours.push_back(b);
graph[b].neighbours.push_back(a);
cap[a][b] = capacity;
cost[a][b] = costs;
cost[b][a] = -costs;
}
bool bf(int startPos, int n, int destination) {
int i, pos;
for ( i = 0; i < n; i++ ) {
dist[i] = INF;
}
dist[startPos] = 1;
q.push(startPos);
graph[startPos].isInQ = true;
while ( !q.empty() ) {
pos = q.front();
graph[pos].isInQ = false;
q.pop();
for ( int x : graph[pos].neighbours ) {
if ( cap[pos][x] > 0 && dist[x] > dist[pos] + cost[pos][x] ) {
dist[x] = dist[pos] + cost[pos][x];
if ( !graph[x].isInQ ) {
graph[x].isInQ = true;
q.push(x);
}
}
}
}
return dist[destination] != INF;
}
bool dijkstra(int startPos, int n, int sink) {
int i;
int pos;
for ( i = 0; i < n; i++ ) {
realDist[i] = dist[i];
virtualDist[i] = INF;
graph[i].visited = false;
}
pq.push({0, startPos});
virtualDist[startPos] = 0;
while ( !pq.empty() ) {
pos = pq.top().b;
pq.pop();
if ( !graph[pos].visited ) {
graph[pos].visited = true;
for ( int x : graph[pos].neighbours ) {
// printf("%d %d\n", virtualDist[x], virtualDist[pos] + cost[pos][x] + realDist[pos] - realDist[x]);
if ( cap[pos][x] > 0 && virtualDist[x] > virtualDist[pos] + cost[pos][x] + realDist[pos] - realDist[x] ) {
virtualDist[x] = virtualDist[pos] + cost[pos][x] + realDist[pos] - realDist[x];
graph[x].parent = pos;
dist[x] = dist[pos] + cost[pos][x];
pq.push({virtualDist[x], x});
}
}
}
}
return virtualDist[sink] != INF;
}
int main() {
FILE *fin, *fout;
fin = fopen("fmcm.in", "r");
fout = fopen("fmcm.out", "w");
int n, m, s, d, i, a, b, costs, capacity, totCost, nod, flow, costForWay;
bool canReach;
fscanf(fin, "%d%d%d%d", &n, &m, &s, &d);
s--;
d--;
for ( i = 0; i < m; i++ ) {
fscanf(fin, "%d%d%d%d", &a, &b, &capacity, &costs);
a--;
b--;
addEdge(a, b, costs, capacity);
}
canReach = bf(s, n, d);
totCost = 0;
if ( canReach ) {
while ( dijkstra(s, n, d) ) {
nod = d;
costForWay = 0;
flow = INF;
while ( nod != s ) {
flow = min(flow, cap[graph[nod].parent][nod]);
costForWay += cost[graph[nod].parent][nod];
nod = graph[nod].parent;
}
totCost += costForWay * flow;
nod = d;
while ( nod != s ) {
cap[graph[nod].parent][nod] -= flow;
cap[nod][graph[nod].parent] += flow;
nod = graph[nod].parent;
}
//printf("\n");
}
}
fprintf(fout, "%d\n", totCost);
fclose(fin);
fclose(fout);
return 0;
}