const int maxn=201;
const int maxm=201;
struct node
{
int x,y,f,op,next; //x起点,y终点,f权值,next是以x为起点的上一条边在g中的位置,op是反向边在g中的下标位置
}g[maxm*2];
//first[]存储的是以x为起点的最后一条边的在数组g中的下标
//sumd[]用于记录表示标号为i的顶点数有多少个,用于间隙优化
int first[maxn],now[maxn],sumd[maxn];
int ncount; //代表结点的总数
int dis[maxn],fanhui[maxn],pre[maxn],tot; //dis[]用于记录距离标号,pre[i]记录i的前驱在g[]中的位置,tot记录边的总数
void add(int x,int y,int c)
{
tot++; //tot记录边的总数
g[tot].x=x;
g[tot].y=y;
g[tot].f=c;
g[tot].op=tot+1; //反向边在g中的下标位置
g[tot].next=first[x]; //记录以x为起点的上一条边在g中的下标位置
first[x]=tot; //以x为起点的边的位置
tot++;
//反向边
g[tot].x=y;
g[tot].y=x;
g[tot].f=0; //反向边的初始网络流为0
g[tot].op=tot-1;
g[tot].next=first[y];
first[y]=tot;
}
//ISAP算法
int maxflow(int src,int des)
{
int i,flow,t,j,tempmin; //i,j用于标识结点,t用于标识结点在g中的位置
bool flag; //用于标识是否找到了允许路径
int sumFlow;
memset(dis,0,sizeof(dis));
memset(sumd,0,sizeof(sumd));
for(i=1;i<=ncount;i++) //遍历所有的结点
now[i]=first[i];
sumd[0]=ncount; //标号为0的结点有ncount个
sumFlow=0; //sumFlow记录最大流,初始化为0
i=src; //i初始化为起点
flow=10000000;
while(dis[src]<ncount)
{
fanhui[i]=flow;
flag=false;
t=now[i];
while(t!=0) //寻找允许路径
{
j=g[t].y;
if((g[t].f>0)&&(dis[j]+1==dis[i])) //允许弧
{
flag=true;
pre[j]=t;
now[i]=t;
if(g[t].f<flow) //找到允许增量
flow=g[t].f;
i=j;
if(i==des) //找到了允许路径
{
sumFlow+=flow;
while(i!=src) //修改残余网络
{
g[pre[i]].f-=flow; //正向边
g[g[pre[i]].op].f+=flow; //反向边
i=g[pre[i]].x;
}
flow=10000000;
}
break;
}
t=g[t].next;
}
if(flag)
continue;
//没有找到允许路径
tempmin=ncount-1;
t=first[i];
while(t!=0)
{
if((g[t].f>0)&&(dis[g[t].y]<tempmin))
{
tempmin=dis[g[t].y];
now[i]=t;
}
t=g[t].next;
}
sumd[dis[i]]--;
if(sumd[dis[i]]==0) break; //间隙优化
dis[i]=tempmin+1; //此处别忘+1,因为d[i]=tempmin{d[j]+1|(i,j)在残留网络中}
sumd[dis[i]]++;
if(i!=src)
{
i=g[pre[i]].x;
flow=fanhui[i];
}
}
return sumFlow;
}
int main()
{
int src,des; //src是起点,des是终点
memset(first,0,sizeof(first)); //初始化first
tot = 0; //tot初始化为0
ncount = n; //初始化ncount为结点总数
for(i=0;i<N;++i)
{
cin>>x>>y>>c;
add(x,y,c);
}
printf("%d\n",maxflow(src,des));
return 0;
}