//EK 最小费用最大流
//只需将最大流中的bfs改为SPFA即可
//注意 若要跑最大费用最大流 只需在加边时将正反边费用分别取反
//跑完最小费用最大流后把mincost取反即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
using namespace std;
int n,m,s,t,maxflow,mincost,cnt=-1;
int head[5001],pre[5001],mflow[5001],mcost[5001],vis[5001];
//pre最短路上每个点所连的前一条边 mflow源点到每个点的最大增量 mcost源点到每个点的最小费用 vis为SPFA数组
struct uio{
int to,nxt,flow,cost;
}edge[100001];
void add(int x,int y,int f,int c)
{
edge[++cnt].nxt=head[x];
edge[cnt].to=y;
edge[cnt].flow=f;
edge[cnt].cost=c;
head[x]=cnt;
}
bool spfa()
{
memset(mflow,0x3f,sizeof(mflow));
memset(mcost,0x3f,sizeof(mcost));
memset(vis,0,sizeof(vis));
queue<int> que;
que.push(s);
mcost[s]=0;
pre[t]=-1;
vis[s]=1;
while(!que.empty())
{
int now=que.front();
que.pop();
vis[now]=0;
for(int i=head[now];i!=-1;i=edge[i].nxt)
{
int y=edge[i].to;
if(edge[i].flow>0&&mcost[y]>mcost[now]+edge[i].cost)//是正边
{
mcost[y]=mcost[now]+edge[i].cost;
pre[y]=i;
mflow[y]=min(mflow[now],edge[i].flow);
if(!vis[y])
{
vis[y]=1;
que.push(y);
}
}
}
}
return pre[t]!=-1;//若能增广到汇点 则其前一条边就会有标记
}
void EK()
{
while(spfa())
{
int now=t;
maxflow+=mflow[t];
mincost+=mcost[t]*mflow[t];
while(now!=s)//一直回溯到源点
{
edge[pre[now]].flow-=mflow[t];
edge[pre[now]^1].flow+=mflow[t];
now=edge[pre[now]^1].to;
}
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++)
{
int u,v,w,p;
scanf("%d%d%d%d",&u,&v,&w,&p);
add(u,v,w,p);
add(v,u,0,-p);
}
EK();
printf("%d %d\n",maxflow,mincost);
return 0;
}