#include<bits/stdc++.h>
using namespace std;
string numeFisier="fmcm";
ifstream fin(numeFisier+".in"); ofstream fout(numeFisier+".out");
#define cin fin
#define cout fout
#define INIT ios_base :: sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define mp make_pair
#define pb push_back
#define ft first
#define sc second
#define ll long long
#define pii pair<int, int>
#define count_bits __builtin_popcount
//#define int ll
/*
Infoarena MinimumCostFlow
O(min(N * M^2 * logN, F * M * logN ) )
MAXN may need to be changed
*/
#define MAXN 355
class MinCostFlow{
public:
int N, M, S, D;
int C[MAXN][MAXN], Cst[MAXN][MAXN];
int InitialC[MAXN][MAXN];
vector<int> con[MAXN];
int F, FCst;
int old_d[MAXN]; char inQ[MAXN];
queue<int> Q;
int d[MAXN], real_d[MAXN], p[MAXN];
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > H;
vector<pair<int,vector<int>>>Paths;
inline bool dijkstra()
{
memset(d, 0x3f, sizeof(d));
d[S] = 0; real_d[S] = 0;
H.push(make_pair(d[S], S));
for (; !H.empty(); )
{
int cst = H.top().first, nod = H.top().second;
H.pop();
if (d[nod] != cst)
continue;
vector<int> :: iterator it;
for (it = con[nod].begin(); it != con[nod].end(); it++)
if (C[nod][*it])
{
int new_d = d[nod] + Cst[nod][*it] + old_d[nod] - old_d[*it];
if (new_d < d[*it])
{
d[*it] = new_d;
real_d[*it] = real_d[nod] + Cst[nod][*it];
p[*it] = nod;
H.push(make_pair(d[*it], *it));
}
}
}
memcpy(old_d, real_d, sizeof(d));
if (d[D] == 0x3f3f3f3f)
return false;
int Min = 0x3f3f3f3f, curCst = 0;
for (int aux = D; aux != S; aux = p[aux])
Min = min(Min, C[p[aux]][aux]),
curCst += Cst[p[aux]][aux];
F += Min;
FCst += Min * real_d[D];
vector<int> path;
for (int aux = D; aux != S; aux = p[aux])
C[p[aux]][aux] -= Min,
C[aux][p[aux]] += Min,
path.push_back(aux);
;
path.push_back(S);
Paths.push_back(mp(Min, path));
return true;
}
inline bool bellmanFord()
{
memset(old_d, 0x3f, sizeof(old_d));
old_d[S] = 0;
for (Q.push(S), inQ[S] = 1; !Q.empty(); Q.pop())
{
vector<int> :: iterator it;
int i = Q.front();
inQ[i] = 0;
for (it = con[i].begin(); it != con[i].end(); it++)
if (C[i][*it])
{
if (old_d[i] + Cst[i][*it] >= old_d[*it])
continue;
old_d[*it] = old_d[i] + Cst[i][*it];
if (inQ[*it])
continue;
inQ[*it] = 1;
Q.push(*it);
}
}
if (old_d[D] == 0x3f3f3f3f)
return false;
return true;
}
void DoFlow( int n, int m, int s/*source*/, int d/*destination,sink */, vector< vector<int> > &Edges ){
N=n, M=m, S=s, D=d;
for(auto vec:Edges){
int x=vec[0], y=vec[1];
C[x][y]=InitialC[x][y]=vec[2];
Cst[x][y]=vec[3];
con[x].push_back(y);
con[y].push_back(x);
Cst[y][x] = -Cst[x][y];
}
F = FCst = 0;
bellmanFord();
for (; dijkstra(); );
//{cout<<"dijk\n";}
}
void Clean(){
for(int i=1; i<=N; i++){
for(int j=1; j<=N; j++){
Cst[i][j]=0;
C[i][j]=0;
InitialC[i][j]=0;
}
con[i].clear();
old_d[i]=0;
inQ[i]=0;
d[i]=0;
real_d[i]=0;
p[i]=0;
}
F=0;
FCst=0;
while(!Q.empty()){
Q.pop();
}
while(!H.empty()){
H.pop();
}
Paths.clear();
}
} Solver=MinCostFlow() ;
int32_t main(){
INIT
int n, m ,s, d;
vector<vector<int>> Edges;
cin>>n>>m>>s>>d;
for(int i=1; i<=m; i++){
int x, y, c, cst;
cin>>x>>y>>c>>cst;
Edges.pb({x, y, c, cst});
}
Solver.DoFlow(n, m, s, d, Edges);
//cout<<Solver.F<<"\n";
//cout<<Solver.FCst;
Solver.Clean();
Solver.DoFlow(n, m, s, d, Edges);
cout<<Solver.FCst;
return 0;
}