#include <fstream>
#include <queue>
#include <vector>
using namespace std;
struct Graph
{
vector<vector<int>> capacity;
vector<vector<int>> costs;
vector<vector<int>> original_costs;
vector<vector<bool>> is_normal;
Graph(int nodes)
: capacity(nodes, vector<int>(nodes, 0)),
costs(nodes, vector<int>(nodes, 0)),
original_costs(nodes, vector<int>(nodes, 0)),
is_normal(nodes, vector<bool>(nodes, false)) {}
int Size() const { return capacity.size(); }
void AddEdge(int a, int b, int cap, int cost)
{
capacity[a][b] = cap;
costs[a][b] = cost;
costs[b][a] = -cost;
original_costs[a][b] = costs[a][b];
original_costs[b][a] = costs[b][a];
is_normal[a][b] = true;
}
};
template <typename T>
using MinHeap = priority_queue<T, vector<T>, greater<T>>;
vector<int> BellmanFord(const Graph &g, int start)
{
vector<int> total(g.Size(), (1 << 30));
total[start] = 0;
queue<int> q;
q.push(start);
while (!q.empty()) {
auto node = q.front();
q.pop();
for (int next = 0; next < g.Size(); next += 1) {
if (g.costs[node][next] == 0 || !g.is_normal[node][next]) {
continue;
}
if (total[node] + g.costs[node][next] < total[next]) {
total[next] = total[node] + g.costs[node][next];
q.push(next);
}
}
}
return total;
}
void MakeCostsPositive(Graph &g, int source)
{
auto total = BellmanFord(g, source);
for (int i = 0; i < g.Size(); i += 1) {
for (int j = 0; j < g.Size(); j += 1) {
if (g.is_normal[i][j] || g.is_normal[j][i]) {
g.costs[i][j] += total[i] - total[j];
}
}
}
}
bool FindPaths(const Graph &g, int source, int dest, vector<int> &pred)
{
pred.assign(g.Size(), -1);
vector<int> costs(g.Size(), (1 << 30));
costs[source] = 0;
MinHeap<pair<int, int>> q;
q.push({0, source});
while (!q.empty()) {
auto cost = q.top().first;
auto node = q.top().second;
q.pop();
if (cost > costs[node]) {
continue;
}
for (int next = 0; next < g.Size(); next += 1) {
if (g.capacity[node][next] <= 0) {
continue;
}
if (cost + g.costs[node][next] < costs[next]) {
costs[next] = cost + g.costs[node][next];
pred[next] = node;
q.push({costs[next], next});
}
}
}
return pred[dest] != -1;
}
int MinCapacity(const Graph &g, int dest, const vector<int> &pred)
{
int node = pred[dest];
int cap = g.capacity[node][dest];
while (node >= 0) {
cap = min(cap, g.capacity[node][dest]);
dest = node;
node = pred[node];
}
return cap;
}
int FlowCost(Graph &g, int dest, const vector<int> &pred)
{
int cap = MinCapacity(g, dest, pred);
int node = pred[dest];
int cost = 0;
while (node >= 0) {
cost += cap * g.original_costs[node][dest];
g.capacity[node][dest] -= cap;
g.capacity[dest][node] += cap;
dest = node;
node = pred[node];
}
return cost;
}
int MinCostFlow(Graph &g, int source, int dest)
{
int cost = 0;
vector<int> pred;
MakeCostsPositive(g, source);
while (FindPaths(g, source, dest, pred)) {
cost += FlowCost(g, dest, pred);
}
return cost;
}
int main()
{
ifstream fin("fmcm.in");
ofstream fout("fmcm.out");
int nodes, edges, source, dest;
fin >> nodes >> edges >> source >> dest;
Graph graph(nodes);
for (int i = 0; i < edges; i += 1) {
int a, b, cap, cost;
fin >> a >> b >> cap >> cost;
graph.AddEdge(a - 1, b - 1, cap, cost);
}
auto cost = MinCostFlow(graph, source - 1, dest - 1);
fout << cost << "\n";
return 0;
}