#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#define REVERSE 1
#define NORMAL 0
std::ifstream fin("fmcm.in");
std::ofstream fout("fmcm.out");
class Edge;
class Graph;
class Edge {
public:
long long source;
long long dest;
long long cap;
long long flow;
long long type;
long long cost;
Edge *reverse;
Edge(){
type = 0;
source = 0;
dest = 0;
cap = 0;
flow = 0;
cost = 0;
}
Edge(long long t=0) : type(t) {
source = 0;
dest = 0;
cap = 0;
flow = 0;
cost = 0;
}
void point(Edge *rev) {
this->reverse = rev;
}
Edge(long long s, long long d, long long c, long long co, long long t = 0) : source(s), dest(d), cap(c), flow(0), type(t), cost(co) {}
};
class Graph {
public:
long long nodes;
std::vector< std::vector<Edge *> > graph;
std::vector<Edge *> all_edges;
std::vector<Edge *> all_revedges;
Graph(int n) : nodes(n) {
graph.reserve(n+1);
}
void addEdge(long long s, long long d, long long c, long long co) {
Edge *e1 = new Edge(s, d, c, co);
Edge *e2 = new Edge(d, s, 0, -co, REVERSE);
e1->point(e2);
e2->point(e1);
graph[s].push_back(e1);
graph[d].push_back(e2);
all_edges.push_back(e1);
all_revedges.push_back(e2);
}
};
namespace BellmanFord {
std::vector<int> bellmanford(const Graph& g, int source) {
std::vector <int> dist(g.nodes + 1, 1e9);
std::vector <int> pred(g.nodes + 1, -1);
dist[source] = 0;
for (int i = 0; i < g.nodes - 1; ++i) {
for (auto edge : g.all_edges) {
if (dist[edge->source] != 1e9 && dist[edge->source] + edge->cost < dist[edge->dest]) {
dist[edge->dest] = dist[edge->source] + edge->cost;
pred[edge->dest] = edge->source;
}
}
}
for (auto edge : g.all_edges) {
if (dist[edge->source] != 1e9 && dist[edge->source] + edge->cost < dist[edge->dest]) {
std::cout << "Graph contains negative cicle\n";
}
}
return dist;
}
void raise(Graph* g, std::vector<int>& distances) {
// for (int i = 1; i <= g->nodes; ++i) {
// std::cout << "\t" << "distance from source to " << i << ": " << distances[i] <<"\n";
// }
for (auto& edge : g->all_edges) {
edge->cost += distances[edge->source] - distances[edge->dest];
}
for (auto& edge : g->all_revedges) {
edge->cost += distances[edge->source] - distances[edge->dest];
}
}
void lower(Graph* g, std::vector<int>& distances) {
for (auto& edge : g->all_edges) {
edge->cost -= distances[edge->source] - distances[edge->dest];
}
for (auto& edge : g->all_revedges) {
edge->cost -= distances[edge->source] - distances[edge->dest];
}
}
}
namespace Dijkstra {
class EdgeEntryComparator {
public:
std::vector<int>& cost;
EdgeEntryComparator(std::vector<int>& _cost) : cost(_cost) {}
bool operator()(int a, int b) {
return this->cost[a] > this->cost[b];
}
};
template <typename T = EdgeEntryComparator>
std::pair< std::vector<int>, std::vector<Edge *> > dijkstra_bef(const Graph& g, int source, std::vector<int>& distances) {
std::vector<int> dist(g.nodes + 1, 1e9);
std::vector<int> real_dist(g.nodes + 1, 1e9);
T comp = T(dist);
std::priority_queue<int, std::vector<int>, T> pq(comp);
std::vector<bool> isinqueue(g.nodes + 1, false);
std::vector<Edge *> bef(g.nodes + 1, nullptr);
dist[source] = 0;
real_dist[source] = 0;
pq.push(source);
isinqueue[source] = true;
while(!pq.empty()) {
int node = pq.top();
pq.pop();
isinqueue[node] = false;
for (auto& edge : g.graph[node]) {
int neigh = edge->dest;
// std:: cout << node << " -> " << neigh << " curent cost: " << dist.at(neigh) << "\n";
if (neigh != node && dist.at(neigh) > dist.at(node) + edge->cost
&& edge->flow < edge->cap) { // added bc of flow
// std:: cout << "Adding: " << node << " -> " << neigh << " :: " << edge->cost << "\n";
dist.at(neigh) = dist.at(node) + edge->cost;
real_dist.at(neigh) = real_dist.at(node) + edge->cost - (distances[edge->source] - distances[edge->dest]);
if (isinqueue[neigh] == false) {
pq.push(neigh);
isinqueue[neigh] = true;
}
bef[neigh] = edge;
}
}
}
for (auto& x : dist) {
if (x == 1e9)
x = -1;
}
return std::make_pair(real_dist, bef);
}
}
long long max_flow_min_cost(Graph& g, long long source, long long dest) {
int total_flow = 0;
int flow_cost = 0;
auto distances_bf = BellmanFord::bellmanford(g, source);
BellmanFord::raise(&g, distances_bf);
while (1) {
auto dist_pred = Dijkstra::dijkstra_bef(g, source, distances_bf);
std::vector<Edge *> predec = dist_pred.second;
std::vector<int> dists = dist_pred.first;
if (predec[dest] == nullptr)
break;
long long flow = 110001;
for (Edge *edge = predec[dest]; edge != nullptr; edge = predec[edge->source]) {
flow = std::min(flow, edge->cap - edge->flow);
}
if (flow == 0)
break;
total_flow += flow;
flow_cost += flow * dists[dest];
for (Edge *edge = predec[dest]; edge != nullptr; edge = predec[edge->source]) {
edge->flow = edge->flow + flow;
edge->reverse->flow = edge->reverse->flow - flow;
}
}
BellmanFord::lower(&g, distances_bf);
return flow_cost;
// long long x = 0;
// for (auto ed : graph[source]) {
// x += ed->flow;
// }
// return x;
}
int main() {
int n, m, so = 1, de;
fin >> n >> m >> so >> de;
Graph g(n);
int s, d, c, co;
for (int i = 0; i < m; ++i) {
fin >> s >> d >> c >> co;
g.addEdge(s, d, c, co);
}
fout << max_flow_min_cost(g, so, de);
}