// Original C++ solution (slower):


#include<iostream>

#include<vector>

#include<algorithm>

#include<queue>



#define INF (1<<29)

#define max_n 10000



using namespace std;



struct edge{int to,cap,rev;};



struct node_t{



  node_t *pp,*lp,*rp;

  int id,val,mini,minId,lazy;

  edge *e;



  node_t(int id,int v):id(id),val(v){

    pp=lp=rp=NULL; lazy=0; update();

  }

   

  inline void update(){

    mini=val,minId=id;

    if(lp && mini>lp->mini)mini=lp->mini,minId=lp->minId;

    if(rp && mini>=rp->mini)mini=rp->mini,minId=rp->minId;

  }

   

  inline void apply(int v){ lazy+=v, val+=v, mini+=v; }

   

  inline void push(){

    if(lp)lp->apply(lazy);

    if(rp)rp->apply(lazy);

    lazy=0;

  }

 

  bool is_root(){

    return !pp || (pp->lp != this && pp->rp != this);

  }



  void rot(bool isl){

    node_t *q=pp,*r=q->pp;

    q->push(),push();

    if(!isl && (q->lp=rp))rp->pp=q;

    if(isl && (q->rp=lp))lp->pp=q;

    (isl?lp:rp)=q;

    q->pp=this;

    if((pp=r)){

      if(r->lp==q)r->lp=this;

      if(r->rp==q)r->rp=this;

    }

    q->update();

  }



  void splay(){

    while(!is_root()){

      node_t *q=pp;

      if(q->is_root()){

	if(q->lp==this)rot(0);

	else rot(1);

      } else {

	node_t *r=q->pp;

	if(r->lp==q){

	  if(q->lp==this){q->rot(0);rot(0);}

	  else {rot(1);rot(0);}

	} else {

	  if(q->rp==this){q->rot(1);rot(1);}

	  else {rot(0);rot(1);}

	}

      }

    }

    push();

    update();

  }

};



void expose(node_t *x){

  node_t *rp=NULL;

  for(node_t *p=x;p;p=p->pp){

    p->splay(),p->rp=rp,p->update(),rp=p;

  }

  x->splay();

}



node_t *find_root(node_t *x){

  expose(x);

  while(x->lp)x=x->lp;

  return x;

}



void cut(node_t *c){

  expose(c);

  node_t *p=c->lp;

  c->lp=NULL;

  p->pp=NULL;

  c->val=INF;

}



void link(node_t *c,node_t *p,int val,edge *e){

  expose(c),expose(p);

  c->pp=p,p->rp=c;

  c->val=val;

  c->update();

  c->e=e;

}



int minId(node_t *x){expose(x); return x->minId;}

void add(node_t *x,int val){ expose(x); x->apply(val); }



vector<edge> g[max_n];

 

void add_edge(int from,int to,int cap){

  g[from].push_back((edge){to,cap,g[to].size()});

  g[to].push_back((edge){from,0,g[from].size()-1});

}

 

int dist[max_n];



bool bfs(int s,int t){

  fill(dist,dist+max_n,-1);

  dist[s]=0;

  queue<int>que;

  que.push(s);

  while(!que.empty()){

    int u=que.front();que.pop();

    if(u==t)return true;

    for(int j=0;j<g[u].size();j++){

      edge e=g[u][j];

      if(dist[e.to]<0 && e.cap>0){

	dist[e.to]=dist[u]+1;

	que.push(e.to);

      }

    }

  }

  return false;

}



int n,ptr[max_n];

node_t *nodes[max_n];

vector<int>lists[max_n];



bool pour(int id,int i){

  int u=lists[id][i];

  if(find_root(nodes[u])==nodes[u])return true;

  edge *e=nodes[u]->e;

  expose(nodes[u]);

  int df=e->cap-nodes[u]->val;

  e->cap-=df;

  g[e->to][e->rev].cap+=df;

  return false;

}



int max_flow(int S,int T){

  int flow=0;

  while(bfs(S,T)){



    fill(ptr,ptr+max_n,0);

    for(int i=0;i<n;i++)nodes[i]=new node_t(i,INF);

    

    node_t *s=nodes[S],*t=nodes[T];

    for(int i=0;i<n;i++)lists[i].clear();

    

    while(true){

      node_t *v=find_root(s);



      if(v==t){

	expose(v=nodes[minId(s)]);

	flow+=v->mini;

	add(s,-v->mini);

	while(true){

	  expose(v=nodes[minId(s)]);

	  if(v->val>0)break;

	  g[v->e->to][v->e->rev].cap+=v->e->cap;

	  v->e->cap=0;

	  cut(v);

	}

	continue;

      } 

      

      if(ptr[v->id] < g[v->id].size()){

	edge &e=g[v->id][ptr[v->id]++];

	if(dist[e.to]==dist[v->id]+1 && e.cap>0){

	  link(v,nodes[e.to],e.cap,&e);

	  lists[e.to].push_back(v->id);

	} 

      } else {

	if(v==s){

	  for(int i=0;i<n;i++){

	    for(int j=0;j<lists[i].size();j++)pour(i,j);

	    lists[i].clear();

	  }

	  break;

	}

	for(int i=0;i<lists[v->id].size();i++){

	  if(!pour(v->id,i))cut(nodes[lists[v->id][i]]);

	}

	lists[v->id].clear();

      }

    }

  }

  return flow;

}



// AOJ GRL_6_A

int main(void){

  

  int e;

  cin >> n >> e;

  for(int i=0;i<e;i++){

    int a,b,c;

    cin >> a >> b >> c;

    add_edge(a,b,c);

  }

 

  cout << max_flow(0,n-1) << endl;;

 

  return 0;

}

// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

#define ALL(A) (A).begin(),(A).end()

#define maxn 1000



using namespace std;



int cap[maxn][maxn],N;



bool dfs(vector<int> &vis,int i,int t){

  if(i==t)return true;

  vis[i]=1;

  for(int j=0;j<N;j++)

    if(!vis[j] && cap[i][j]>0 && dfs(vis,j,t)){

      cap[i][j]--,cap[j][i]++;

      return true;

    }

  return false;

}



int max_flow(int s, int t){

  vector<int>vis(N);

  for(int flow=0;;flow++,fill(ALL(vis),0))

    if(!dfs(vis,s,t))return flow;

}



int main(void){ 

  int e,a,b,c;

  cin >> N >> e;

  for(int i=0;i<e;i++){

    cin >> a >> b >> c;

    cap[a][b]=c;

  }

  cout << max_flow(0,N-1) << endl;;

}

// Fastest known solution for this problem: