#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <algorithm>
#include <utility>
#include <functional>
#include <cstring>
#include <queue>
#include <stack>
#include <math.h>
#include <iterator>
#include <vector>
#include <string>
#include <set>
#include <math.h>
#include <iostream>
#include <map>
#include <iomanip>
#include <time.h>
#include <stdlib.h>
#include <list>
#include <typeinfo>
#include <list>
#include <set>
#include <cassert>
#include<fstream>
#include <cstdlib>
#include <unordered_map>
using namespace std;
#define Ma_PI 3.141592653589793
#define eps 0.00000001
#define LONG_INF 3000000000000000000
#define GOLD 1.61803398874989484820458
#define MAX_MOD 1000000007 
#define REP(i,n) for(long long i = 0;i < n;++i)
#define seg_size 524288
using namespace std;
vector<pair<int,int>> backing[2000];
long long dp[2000] = {};
int visited[2000] = {};
vector<tuple<int, int, int>> vertexs[2000];
vector<tuple<int, int, int>> flowing[2000];
int main() {
	int n, m;
	cin >> n >> m;
	int a, b;
	cin >> a >> b;
	for (int i = 0; i < m; ++i) {
		int a, b, c, d;
		cin >> a >> b >> c >> d;
		vertexs[a].push_back(make_tuple(b,c,d));
	}
	for (int i = 0; i < 2000; ++i) dp[i] = 10000000;
	dp[a] = 0;
	priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> next;
	next.push(make_pair(0, a));
	while (next.empty() == false) {
		pair<int, int> now = next.top();
		next.pop();
		if (visited[now.second] == 0) {
			visited[now.second] = 1;
			for (int i = 0; i < vertexs[now.second].size(); ++i) {
				int nexting = get<0>(vertexs[now.second][i]);
				if (dp[nexting] > now.first + get<1>(vertexs[now.second][i])) {
					dp[nexting] = now.first + get<1>(vertexs[now.second][i]);
					next.push(make_pair(dp[nexting], nexting));
					backing[nexting].clear();
				}
				if (dp[nexting] == now.first + get<1>(vertexs[now.second][i])) {
					backing[nexting].push_back(make_pair(now.second, get<2>(vertexs[now.second][i])));
				}
			}
		}
	}
	for (int i = 0; i < 2000; ++i) {
		visited[i] = 0;
	}
	queue<int> nexting;
	nexting.push(b);
	visited[b] = 1;
	while (nexting.empty() == false) {
		int now = nexting.front();
		nexting.pop();
		for (int i = 0; i < backing[now].size(); ++i) {
			if (visited[backing[now][i].first] == 0) {
				visited[backing[now][i].first] = 1;
				nexting.push(backing[now][i].first);
			}
			flowing[now].push_back(make_tuple(backing[now][i].first,0, 0));
			flowing[backing[now][i].first].push_back(make_tuple(now, backing[now][i].second, flowing[now].size() - 1));
			get<2>(flowing[now][flowing[now].size() - 1]) = flowing[backing[now][i].first].size() - 1;
		}
	}
	long long ans = 0;
	while (true) {
		int ok = 0;
		int visited[300] = {};
		pair<int, int> backing[300] = {};
		priority_queue<tuple<int,int,int>,vector<tuple<int,int,int>>,greater<tuple<int,int,int>>> next;
		next.push(make_tuple(0,a, 1000000));
		while (next.empty() == false) {
			tuple<int,int,int> gekoa = next.top();
			pair<int, int> now = make_pair(get<1>(gekoa), get<2>(gekoa));
			next.pop();
			if (now.first == b&&now.second != 0) {
				ok = 1;
				//going back
				ans += get<0>(gekoa);
				while (now.first != a) {
					int edge = backing[now.first].second;
					int there = backing[now.first].first;
					get<1>(flowing[there][edge]) -= now.second;
					get<1>(flowing[now.first][get<2>(flowing[there][edge])]) += now.second;
					now.first = there;
				}
				break;
			}
			for (int i = 0; i < flowing[now.first].size(); ++i) {
				if (visited[get<0>(flowing[now.first][i])] == 0&&get<1>(flowing[now.first][i]) != 0) {
					visited[get<0>(flowing[now.first][i])] = 1;
					backing[get<0>(flowing[now.first][i])] = make_pair(now.first, i);
					next.push(make_tuple(min(now.second, get<1>(flowing[now.first][i])),get<0>(flowing[now.first][i]), min(now.second, get<1>(flowing[now.first][i]))));
				}
			}
		}
		if (ok == 0) break;
	}
	cout << ans << endl;
	return 0;
}


Measured memory_bytes: 3332