#include <bits/stdc++.h>
using namespace std;
const int N=10010, M=200010,inf=1e9;
int n,m,S,T;
int ver[M],fl[M],nxt[M],head[N],tot=1; //tot=1:边成对存储
int q[N],d[N],nh[N]; //nh: new head
void add(int x,int y,int c){ //++tot出现在前,循环判断用i就可以
ver[++tot]=y,fl[tot]=c,nxt[tot]=head[x],head[x]=tot;
}
bool bfs(){
memset(d,0,sizeof d); //d: 分层用
d[S]=1,q[0]=S,nh[S]=head[S]; //d[S]必须等于1,0用于判读没使用
int hh=0,tt=1;
while(hh<tt){
int x=q[hh++];
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(d[y] || !fl[i])continue;
d[y]=d[x]+1, nh[y]=head[y];
if(y==T)return true;
q[tt++]=y;
}
}
return false;
}
int find(int x,int limit){
if(x==T)return limit;
int flow=0;
for(int i=nh[x];i && flow<limit;i=nxt[i]){ //flow等于limit,用完了配额
int y=ver[ nh[x]=i ]; //nh[x]在这里更新
if(d[y]!=d[x]+1 || !fl[i])continue; //y必须是x的下一层
int t=find(y,min(fl[i],limit-flow)); //y点用了配额t
if(t)flow+=t, fl[i]-=t, fl[i^1]+=t; //边成对更新
else d[y]=0; //y此时已废
}
return flow;
}
int dinic(){
int res=0,flow;
for(;bfs();) //没使用连续2个while,以示两个循环意义不同
while(flow=find(S,inf)) res+=flow;
return res;
}
int main(){
cin>>n>>m>>S>>T;
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c), add(b,a,0);
}
printf("%d\n",dinic());
return 0;
}