#include<bits/stdc++.h>
using namespace std;
using ll=long long;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
#define ll __int128
#define pb push_back
#define all(a) a.begin(),a.end()
#define sz(a) ((int)a.size())
const int N=1005,M=2005;
template<typename T1, typename T2>
struct MCMF{
const T1 INF1=1<<30;
const T2 INF2=1<<30;
struct edge{
int v; T1 f; T2 c;
}E[M<<1];
vector<int> adj[N];
T2 dis[N],pot[N];
int rt[N],vis[N],n,m,s,t;
bool SPFA(){
fill_n(rt,n,-1),fill_n(dis,n,INF2);
fill_n(vis,n,false);
queue<int> q;
q.push(s),dis[s]=0,vis[s]=true;
while(!q.empty()){
int v=q.front(); q.pop();
vis[v]=false;
for(int id: adj[v]){
auto [u,f,c]=E[id];
T2 ndis=dis[v]+c+pot[v]-pot[u];
if(f>0&&dis[u]>ndis){
dis[u]=ndis,rt[u]=id;
if(!vis[u]) vis[u]=true,q.push(u);
}
}
}
return dis[t]!=INF2;
}
bool dijkstra(){
fill_n(rt,n,-1),fill_n(dis,n,INF2);
priority_queue<pair<T2,int>,vector<pair<T2,int>>,greater<pair<T2,int>>> pq;
dis[s]=0,pq.emplace(dis[s],s);
while(!pq.empty()){
auto [d,v]=pq.top(); pq.pop();
if(dis[v]<d) continue;
for(int id: adj[v]){
auto [u,f,c]=E[id];
T2 ndis=dis[v]+c+pot[v]-pot[u];
if(f>0&&dis[u]>ndis){
dis[u]=ndis,rt[u]=id;
pq.emplace(ndis,u);
}
}
}
return dis[t]!=INF2;
}
vector<pair<T1,T2>> solve(int _s, int _t){
s=_s,t=_t,fill_n(pot,n,0);
T1 flow=0; T2 cost=0; bool fr=true;
vector<pair<T1,T2>> res;
res.pb({0,0});
while(fr?SPFA():dijkstra()){
for(int i=0; i<n; ++i) dis[i]+=pot[i]-pot[s];
T1 add=INF1;
for(int i=t; i!=s; i=E[rt[i]^1].v) add=min(add,E[rt[i]].f);
for(int i=t; i!=s; i=E[rt[i]^1].v) E[rt[i]].f-=add,E[rt[i]^1].f+=add;
flow+=add,cost+=add*dis[t],fr=false;
res.pb({flow,cost});
for(int i=0; i<n; ++i) swap(dis[i],pot[i]);
}
return res;
}
void init(int _n){
n=_n,m=0;
for(int i=0; i<n; ++i) adj[i].clear();
}
void add_edge(int u, int v, T1 f, T2 c){
adj[u].pb(m),E[m++]={v,f,c};
adj[v].pb(m),E[m++]={u,0,-c};
}
};
MCMF<ll,ll> g;
int n,m,s,t;
pll operator + (pll a, pll b){return {a.first*b.second+b.first*a.second,a.second*b.second};}
pll operator - (pll a, pll b){return {a.first*b.second-b.first*a.second,a.second*b.second};}
pll operator * (pll a, pll b){return {a.first*b.first,a.second*b.second};}
bool cmp(pll a, pll b){return a.first*b.second<b.first*a.second;}
void chmin(pll &a, pll b){if(cmp(b,a)) a=b;}
signed main(){
cin >> n >> m >> s >> t; s--,t--;
g.init(n);
for(int i=0; i<m; ++i){
int a,b,u,c; cin >> a >> b >> u >> c; a--,b--;
g.add_edge(a,b,u,c);
}
vector<pll> vec=g.solve(s,t);
ll mx=vec.back().first;
#define sq(x) ((x)*(x))
pll res={sq(mx),1};
for(int i=0; i<sz(vec); ++i) chmin(res,pll(sq(vec[i].second)+sq(mx-vec[i].first),1));
//for(auto &[i,j]: vec) cout << i << ' ' << j << endl;
for(int i=0; i+1<sz(vec); ++i){
ll a1=vec[i].first,a2=vec[i].second;
ll b=(vec[i+1].second-vec[i].second)/(vec[i+1].first-vec[i].first);
pll cur={mx-a1-a2*b,b*b+1};
if(cur.first>0&&cur.first<cur.second*(vec[i+1].first-vec[i].first)){
pll de1=pll(a2,1)+cur*pll(b,1),de2=pll(mx-a1,1)-cur;
chmin(res,sq(de1)+sq(de2));
}
}
ll g=__gcd(res.first,res.second);
res.first/=g,res.second/=g;
cout << ((long long)res.first) << '/' << ((long long)res.second) << "\n";
}