#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
struct node
{
int y,next,other;
ll c,k;
}a[201000];int last[1000],len;
long long d[1100];
bool v[1100];
int n,m,st,ed;
ll cost=0;
inline void ins(int x,int y,ll c,ll k)
{
len++;
a[len].y=y;a[len].c=c;a[len].k=k;
a[len].next=last[x];last[x]=len;
len++;
a[len].y=x;a[len].c=0;a[len].k=-k;
a[len].next=last[y];last[y]=len;
a[len-1].other=len;
a[len].other=len-1;
}
int list[1100],head,tail;/*队列*/
inline bool spfa()
{
memset(v,false,sizeof(v));v[ed]=true;/*判断是否进入队列*/
memset(d,-1,sizeof(d));d[ed]=0;/*从终点到这里要多少费用*/
head=1;tail=2;list[head]=ed;/*从终点出发*/
while(head!=tail)
{
int x=list[head];
for(int k=last[x];k;k=a[k].next)
{
if(a[a[k].other].c>0/*由于是倒着搜的,所以边也要反向边*/ && (a[a[k].other].k+d[x]<d[a[k].y] || d[a[k].y]==-1))/*判断边是否可行并更新*/
{
d[a[k].y]=a[a[k].other].k+d[x];/*更新*/
int y=a[k].y;
if(v[y]==false)
{
v[y]=true;
list[tail]=y;
tail++;
if(tail==n+1)tail=1;
}
}
}
head++;
if(head==n+1)head=1;
v[x]=false;
}
return d[st]!=-1;/*返回bool值*/
}
inline ll mymin(ll x,ll y){return x<y?x:y;}/*找最小值*/
long long find(int x,ll f)
{
v[x]=true;
if(x==ed){v[x]=false;return f;}
ll ans=0,t=0;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(v[y]==false/*这个点没走过才可以走,否则更新边的流量是会Balabala*/ && a[k].c>0 && d[x]-a[k].k==d[y]/*类似分层的操作*/ && ans<f)
{
ans+=t=find(y,mymin(a[k].c,f-ans));/*是不是很眼熟?*/
a[k].c-=t;a[a[k].other].c+=t;cost+=t*a[k].k;
}
}
v[x]=false;
return ans;/*妥妥的像最大流*/
}
int main()
{
scanf("%d%d",&n,&m);
st=1;ed=n;
for(int i=1;i<=m;i++)
{
int x,y;
ll z,l;
scanf("%d%d%lld%lld",&x,&y,&z,&l);
ins(x,y,z,l);
}
ll zans=0;
while(spfa()==true)/*建图完成!*/
{
zans+=find(st,ll(999999999999999));/*多次查找,找出所有增光路哦*/
}
printf("%lld %lld",zans,cost);
return 0;
}