#include <bits/stdc++.h>
using namespace std;
class InParser{
private:
FILE *fin;
char *buff;
int sp;
char read_ch(){
if (++sp == 4096)
sp = 0, fread(buff, 1, 4096, fin);
return buff[sp];
}
public:
InParser (const char* nume){
fin = fopen(nume, "r");
buff = new char[4096];
sp = 4095;
}
InParser& operator>> (int &n){
char c;
while (!isdigit(c = read_ch()) && c != '-');
int sgn = 1;
if (c == '-')
n = 0, sgn = -1;
else
n = c - '0';
while (isdigit(c = read_ch()))
n = 10 * n + c - '0';
n *= sgn;
return *this;
}
};
struct Graph{
int n, s, d;
vector < vector <int> > graph;
vector < vector <int> > cap, cost;
vector <int> dist, dist2, pr;
queue < pair <int, int> > Q;
priority_queue < pair <int, int> > S;
Graph(int _n, int _s, int _d): n(_n), s(_s), d(_d), graph(n),
cap(n, vector <int>(n)), cost(n, vector <int>(n)),
dist(n), dist2(n), pr(n) { }
void AddEdge(int a, int b, int cp, int cst){
graph[a].push_back(b);
graph[b].push_back(a);
cap[a][b] += cp;
cost[a][b] = cst;
cost[b][a] = -cst;
}
void Bellman(){
fill(dist.begin(), dist.end(), 1e9);
vector <bool> vis(n);
Q.push({0, s});
dist[s] = 0;
vis[s] = 1;
while (!Q.empty()){
int curr_cost = Q.front().first;
int node = Q.front().second;
Q.pop();
if (curr_cost != dist[node])
continue;
for (auto nei: graph[node]){
if (!cap[node][nei])
continue;
int new_cost = curr_cost + cost[node][nei];
if (new_cost < dist[nei]){
dist[nei] = curr_cost;
if (!vis[nei]){
Q.push({dist[nei], nei});
vis[nei] = 1;
}
}
}
vis[node] = 0;
}
}
int Dijkstra(){
fill(dist2.begin(), dist2.end(), 1e9);
S.push({0, s});
dist2[s] = 0;
pr[s] = -1;
while (!S.empty()){
int curr_cost = -S.top().first;
int node = S.top().second;
S.pop();
if (curr_cost != dist2[node])
continue;
for (auto nei: graph[node]){
if (!cap[node][nei])
continue;
int new_cost = curr_cost + cost[node][nei] + dist[node] - dist[nei];
if (new_cost < dist2[nei]){
dist2[nei] = new_cost;
pr[nei] = node;
S.push({-dist2[nei], nei});
}
}
}
if (dist2[d] == 1e9)
return 0;
int flow = 1e9;
int path_cost = 0;
for (int node = d; node != s; node = pr[node])
flow = min(flow, cap[pr[node]][node]);
for (int node = d; node != s; node = pr[node]){
cap[pr[node]][node] -= flow;
cap[node][pr[node]] += flow;
path_cost += cost[pr[node]][node];
}
dist = dist2;
return flow * path_cost;
}
int MinCostMaxFlow(){
Bellman();
int ans = 0;
while (auto iterate = Dijkstra()){
ans += iterate;
}
return ans;
}
};
int main(){
InParser cin("fmcm.in");
ofstream cout("fmcm.out");
int n, m, s, d;
cin >> n >> m >> s >> d;
s--; d--;
Graph G(n, s, d);
while(m--){
int a, b, c, z;
cin >> a >> b >> c >> z;
a--; b--;
G.AddEdge(a, b, c, z);
}
cout << G.MinCostMaxFlow() << '\n';
return 0;
}