#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int NMAX = 350;
const int INF = 2.e9;
vector <int> G[NMAX + 5];
int d[NMAX + 5] , cap[NMAX + 5][NMAX + 5] , cst[NMAX + 5][NMAX + 5] , p[NMAX + 5] , n;
struct path
{
int nod , cost;
path(int x = 0 , int y = 0)
{
nod = x;
cost = y;
}
};
bool operator<(const path& a , const path& b)
{
return a.cost > b.cost;
}
int dijkstra(int s , int t)
{
int i , u , v , cost , new_cost;
for(i = 1 ; i <= n ; i ++)
d[i] = INF;
d[s] = 0;
priority_queue <path> pq;
pq.push(path(s , 0));
while(!pq.empty())
{
u = pq.top().nod;
cost = pq.top().cost;
pq.pop();
if(d[u] < cost)
continue;
for(i = 0 ; i < G[u].size() ; i ++)
{
v = G[u][i];
if(cap[u][v])
{
new_cost = d[u] + cst[u][v];
if(new_cost < d[v])
{
d[v] = new_cost;
p[v] = u;
pq.push(path(v , new_cost));
}
}
}
}
if(d[t] == INF)
return 0;
return 1;
}
inline int get_flow(int s , int t)
{
int flow , nod;
flow = INF;
for(nod = t ; nod != s ; nod = p[nod])
flow = min(flow , cap[p[nod]][nod]);
return flow;
}
inline int set_flow(int s , int t , int flow)
{
for(int nod = t ; nod != s ; nod = p[nod])
{
cap[p[nod]][nod] = cap[p[nod]][nod] - flow;
cap[nod][p[nod]] = cap[nod][p[nod]] + flow;
}
return flow * d[t];
}
int fmcm(int s , int t)
{
int cost = 0;
while(dijkstra(s , t))
cost += set_flow(s , t , get_flow(s , t));
return cost;
}
int main()
{
freopen("fmcm.in" , "r" , stdin);
freopen("fmcm.out" , "w" , stdout);
int m , s , t , i , j , x , y , c , z;
scanf("%d%d%d%d" , &n , &m , &s , &t);
for(i = 1 ; i <= m ; i ++)
{
scanf("%d%d%d%d" , &x , &y , &c , &z);
G[x].push_back(y);
G[y].push_back(x);
cap[x][y] = c;
cst[x][y] = z;
cst[y][x] = -z;
}
printf("%d\n" , fmcm(s , t));
return 0;
}