#include <bits/stdc++.h>
struct Edge {
int from;
int to;
int capacity;
int cost;
int flow;
int normalised_cost;
};
typedef std::vector<std::vector<int>> Graph_t;
const int kInf = 0x3f3f3f3f;
void bellmanFord( const int &source, const int &nodeCount
, const Graph_t &graph
, const std::vector<Edge> &edges
, std::vector<int> *distance) {
distance->assign(nodeCount, kInf);
distance->at(source) = 0;
std::vector<bool> inQueue(nodeCount, false);
std::queue<int> queue;
queue.push(source);
inQueue[source] = true;
while (!queue.empty()) {
int currNode = queue.front();
queue.pop();
inQueue[currNode] = false;
for (int edgeIndex : graph[currNode]) {
if (distance->at(edges[edgeIndex].to) > distance->at(currNode)
+ edges[edgeIndex].cost
&& edges[edgeIndex].capacity > edges[edgeIndex].flow) {
distance->at(edges[edgeIndex].to) = distance->at(currNode)
+ edges[edgeIndex].cost;
if (!inQueue[edges[edgeIndex].to]) {
queue.push(edges[edgeIndex].to);
inQueue[edges[edgeIndex].to] = true;
}
}
}
}
}
void normaliseEdges( std::vector<Edge> *edges
, const std::vector<int> &distance) {
for (Edge& edge : *edges) {
edge.normalised_cost =
edge.cost + distance[edge.from] - distance[edge.to];
}
}
bool dijkstra( const int &nodeCount, const int &source, const int &destination
, const Graph_t &graph
, const std::vector<Edge> &edges
, int *minCost
, std::vector<int> *prev
, std::vector<int> *realDistance) {
realDistance->assign(nodeCount, kInf);
realDistance->at(source) = 0;
std::vector<int> distance(nodeCount, kInf);
distance[source] = 0;
prev->assign(nodeCount, -1);
std::priority_queue<std::pair<int, int>> pq;
pq.emplace(0, source);
std::vector<bool> fixed(nodeCount, false);
while (true) {
while (!pq.empty() && -pq.top().first != distance[pq.top().second])
pq.pop();
if (pq.empty())
break;
int currNode = pq.top().second;
int currDist = -pq.top().first;
fixed[currNode] = true;
pq.pop();
for (int edgeIndex : graph[currNode]) {
// assert(edges[edgeIndex].normalised_cost >= 0 || edges[edgeIndex].flow == edges[edgeIndex].capacity);
if ( edges[edgeIndex].flow < edges[edgeIndex].capacity
&& distance[edges[edgeIndex].to] >
currDist + edges[edgeIndex].normalised_cost
) {
distance[edges[edgeIndex].to] =
currDist + edges[edgeIndex].normalised_cost;
realDistance->at(edges[edgeIndex].to) =
realDistance->at(currNode) + edges[edgeIndex].cost;
if (edges[edgeIndex].to == destination && realDistance->at(destination) == 51) {
// std::cerr << currNode << ' ' << realDistance->at(currNode) << ' ' << edges[edgeIndex].cost << std::endl;
}
prev->at(edges[edgeIndex].to) = edgeIndex;
pq.emplace(-distance[edges[edgeIndex].to], edges[edgeIndex].to);
}
}
}
*minCost = realDistance->at(destination);
return prev->at(destination) != -1;
}
int64_t getMinCostForMaxFlow( const int &nodeCount
, const int &source
, const int &destination
, const Graph_t &graph
, std::vector<Edge> *edges) {
int64_t minCost = 0;
std::vector<int> prev, realDistance;
int minCostPath;
// int cnt = 16;
while (dijkstra( nodeCount, source, destination, graph, *edges
, &minCostPath, &prev, &realDistance)) {
int addFlow = kInf, cst = 0;
for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from]) {
addFlow = std::min( addFlow
, edges->at(idx).capacity - edges->at(idx).flow);
cst += edges->at(idx).cost;
// if (cnt) std::cerr << edges->at(idx).to + 1 << ' ';
}
for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from]) {
edges->at(idx).flow += addFlow;
edges->at(idx ^ 1).flow -= addFlow;
}
minCost += 1LL * minCostPath * addFlow;
// normaliseEdges(edges, realDistance);
// if (cnt) {std::cerr << std::endl << addFlow << ' ' << minCostPath << " " << cst << " " << realDistance[destination] << std::endl; cnt--;}
// if (cnt && minCostPath != cst) {
// std::cerr << "HERE\n";
// for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from]) {
// std::cerr << edges->at(idx).cost << ' ';
// }
// std::cerr << std::endl;
// for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from])
// std::cerr << realDistance[edges->at(idx).to] << ' ';
// std::cerr << realDistance[source] << std::endl;
// for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from])
// std::cerr << edges->at(idx).to << ' ';
// std::cerr << source << std::endl;
// }
}
return minCost;
}
int main() {
std::ifstream cin("fmcm.in");
std::ofstream cout("fmcm.out");
int nodeCount, edgeCount;
cin >> nodeCount >> edgeCount;
int source, destination;
cin >> source >> destination;
source--; destination--; // index nodes from 0
std::vector<Edge> edges(2 * edgeCount);
Graph_t graph(nodeCount);
for (int i = 0; i < edgeCount; ++i) {
int from, to, capacity, cost;
cin >> from >> to >> capacity >> cost;
// index nodes from 0
from--; to--;
edges[2*i] = Edge {from, to, capacity, cost, 0, 0};
graph[from].push_back(2*i);
edges[2*i + 1] = Edge {to, from, 0, -cost, 0, 0};
graph[to].push_back(2*i + 1);
}
std::vector<int> distance;
bellmanFord(source, nodeCount, graph, edges, &distance);
normaliseEdges(&edges, distance);
cout << getMinCostForMaxFlow(nodeCount, source, destination, graph, &edges)
<< std::endl;
return 0;
}
//Trust me, I'm the Doctor!