#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <cstring>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <unordered_set>
#include <unordered_map>
#include <array>
#include <cassert>
#include <bitset>
using namespace std;
using LL = long long;


class dinic {
private:
	struct edge {
		int to; long long cap; int rev;
		edge(int t_, long long c_, int r_) :to(t_), cap(c_), rev(r_) {}
	};
	vector<vector<edge> >G; vector<int>level, iter;
	//sourceからBFSをする
	void bfs(int s_) {
		fill(level.begin(), level.end(), -1);
		std::queue<int>que;
		level[s_] = 0;
		que.push(s_);
		while (!que.empty()) {
			int v = que.front(); que.pop();
			for (int i = 0; i < G[v].size(); ++i) {
				edge &e = G[v][i];
				if (e.cap > 0 && level[e.to] < 0) {
					level[e.to] = level[v] + 1;
					que.push(e.to);
				}
			}
		}
	}
	//DFSで増加パスを見つけて、流す。
	long long dfs(int v_, int t_, long long f_) {
		if (v_ == t_)return f_;
		for (int &i = iter[v_]; i < G[v_].size(); ++i) {
			edge &e = G[v_][i];
			if (e.cap > 0 && level[v_] < level[e.to]) {
				long long d = dfs(e.to, t_, min(f_, e.cap));
				if (d > 0) {
					e.cap -= d;
					G[e.to][e.rev].cap += d;
					return d;
				}
			}
		}
		return 0;
	}
public:
	dinic(int vec_) :G(vec_), level(vec_), iter(vec_) {}
	//fromからtoへ容量capの辺を張る
	void add_edge(int from_, int to_, long long cap_) {
		G[from_].push_back(edge(to_, cap_, G[to_].size()));
		G[to_].push_back(edge(from_, 0ll, G[from_].size() - 1));
	}
	//Dinic法で、頂点source→sinkの最大流量を計算する 最悪計算量O(V^2*E)
	long long max_flow(int source_, int sink_) {
		long long flow = 0;
		for (;;) {
			bfs(source_);
			if (level[sink_] < 0)return flow;
			fill(iter.begin(), iter.end(), 0);
			for (;;) {
				long long f = dfs(source_, sink_, LLONG_MAX);
				if (f > 0)flow += f;
				else break;
			}
		}
		return flow;
	}
};

int N, M;
int s, t;
int pool;
void addEdge(int u, int v, int d, int c, dinic& D) {
	vector<int>path;
	path.push_back(u);
	for (int x = 1; x < d; ++x) {
		path.push_back(pool);
		pool++;
	}
	path.push_back(v);
	for (int ind = 1; ind < path.size(); ++ind) {
		int u = path[ind - 1];
		int v = path[ind];
		D.add_edge(u, v, c);
	}
}

LL rG[222][222];
vector<pair<int, pair<int, int>>>graph[44444];

int main(void)
{
	cin >> N >> M >> s >> t;
	pool = N;
	--s; --t;
	for (int i = 0; i < 222; ++i)
		for (int j = 0; j < 222; ++j)
			rG[i][j] = ((i == j) ? 0LL : 1234567891023LL);
	for (int i = 0; i < M; ++i) {
		int u, v, d, c;
		cin >> u >> v >> d >> c;
		--u; --v;
		graph[u].push_back({ v,{d,c} });
		rG[u][v] = d;
	}
	for (int k = 0; k < N; ++k) {
		for (int i = 0; i < N; ++i) {
			for (int j = 0; j < N; ++j) {
				rG[i][j] = min(rG[i][j], rG[i][k] + rG[k][j]);
			}
		}
	}
	dinic flow(44444);
	int stDist = rG[s][t];
	for (int v = 0; v < N; ++v) {
		for (auto& e : graph[v]) {
			int to = e.first;
			int d = e.second.first;
			int c = e.second.second;
			int nowDist = rG[s][v] + d + rG[to][t];
			if (stDist == nowDist) {
				addEdge(v, to, d, c, flow);
			}
		}
	}
	int ans = flow.max_flow(s, t);
	cout << ans << endl;
	return 0;
}



Measured memory_bytes: 5780