#include<stdio.h>
#include<string.h>
#include<math.h>
#include<cmath>
#include<cstdio>
#include<cstring>
#define N 10005
#define X 1000000
#define mem(a) memset(a,-1,sizeof(a))
#include<algorithm>
using namespace std;
struct node
{
int c,f;//容量和流量
};
node Edge[N][N];//邻接矩阵
int n;//顶点个数
int flag[N];//顶点状态,-1未标记,0已标记未检查,1已标记已检查
int prev[N];//标号的第一个分量:指明标号从哪个顶点得到,以便找出可改进量
int alpha[N];//标号的第二个分量,可改进a
int queue[N];//队列模拟
int head,tail;
void ford()
{
while(1)
{
mem(flag),mem(prev),mem(alpha);//初始化
flag[0]=0,prev[0]=0,alpha[0]=X;//源点处理
head=tail=0;
queue[tail++]=0;
while(head<tail&&flag[n-1]==-1)//队列不为空&&汇点未标号
{
int v=queue[head++];
for(int i=0; i<n; i++)//检查顶点v的正向和反向邻接顶点
{
if(flag[i]==-1)//顶点i未标号
{
if(Edge[v][i].c<X&&Edge[v][i].f<Edge[v][i].c)//正向且未满
{
flag[i]=0;
prev[i]=v;
alpha[i]=min(alpha[v],Edge[v][i].c-Edge[v][i].f);
queue[tail++]=i;
}
else if(Edge[i][v].c<X&&Edge[i][v].f>0)//反向且有流量
{
flag[i]=0;//给顶点标号(已标未检查)
prev[i]=-v;
alpha[i]=min(alpha[v],Edge[i][v].f);
queue[tail++]=i;
}
}
}
flag[v]=1;//顶点v已标号已检查
}
if(flag[n-1]==-1||alpha[n-1]==0)break;//当汇点没有获得标号或者汇点调整量为0,退出循环
int a=alpha[n-1];/*可改进量*/
// int k1=n-1,k2=abs(prev[k1]);
// while(1)
// {
// if(Edge[k2][k1].f<X)
// Edge[k2][k1].f+=a;//正向
// else
// Edge[k1][k2].f-=a;//反向
// if(k2==0)
// break;
// k1=k2;
// k2=abs(prev[k2]);
// }
for(int j=n-1,i=abs(prev[j]); ; j=i,i=abs(prev[i]))//调整一直到源点
{
if(Edge[i][j].f<X)
Edge[i][j].f+=a;//正向
else
Edge[j][i].f-=a;//反向
if(i==0)
break;
}
}
int maxx=0;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
{
if(i==0&&Edge[i][j].f<X)//求源点流出量
maxx+=Edge[i][j].f;
if(Edge[i][j].f<X)
printf("%d->%d : %d\n",i,j,Edge[i][j].f);
}
printf("%d\n",maxx);
}
int main()
{
int u,v,c,f;//弧起点,重点,容量,流量
scanf("%d",&n);
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
Edge[i][j].c=Edge[i][j].f=X;//表示没有直接边连接
while(~scanf("%d%d%d%d",&u,&v,&c,&f)&&(u!=-1||v!=-1||c!=-1||f!=-1))//构造邻接矩阵
{
Edge[u][v].c=c;
Edge[u][v].f=f;
}
ford();//标号法求网络最大流
}
//6
//0 1 8 2
//0 2 4 3
//1 3 2 2
//1 4 2 2
//2 1 4 2
//2 3 1 1
//2 4 4 0
//3 4 6 0
//3 5 9 3
//4 5 7 2
//-1 -1 -1 -1