#include<bits/stdc++.h>
using namespace std;
#define N 2010
#define M 200010
#define INF 0x3f3f3f3f
inline int read()
{
int s=0,f=1;
char ch=getchar();
while(ch<'0'||'9'<ch) {if(ch=='-')f=-1;ch=getchar();}
while('0'<=ch&&ch<='9') {s=s*10+ch-'0';ch=getchar();}
return s*f;
}
int n,m,S,T;
vector<int>head,to,nxt,val;
int ht[N],ex[N],gap[N];//高度,超额流,gap优化
void join(int u,int v,int w)
{
nxt.push_back(head[u]);
head[u]=to.size();
to.push_back(v);
val.push_back(w);
}
bool bfs()
{
queue<int>q;
for(int i=1;i<=n;++i)
{
ht[i]=INF;
}
while(!q.empty())
{
q.pop();
}
q.push(T),ht[T]=0;//汇点跑源点 反向跑所以是i^1
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];i!=-1;i=nxt[i])
{
if(val[i^1]&&ht[to[i]]>ht[u]+1)
{
ht[to[i]]=ht[u]+1;
q.push(to[i]);
}
}
}
return ht[S]!=INF;
}
struct cmp
{
bool operator()(int a,int b){return ht[a]<ht[b];}
};
priority_queue<int,vector<int>,cmp>q;
bool vis[N];
bool push(int u)
{
for(int i=head[u];i!=-1;i=nxt[i])
{
if(val[i]&&ht[u]==ht[to[i]]+1)
{
int tmp=min(val[i],ex[u]);
ex[u]-=tmp;
ex[to[i]]+=tmp;
val[i]-=tmp;
val[i^1]+=tmp;
if(to[i]!=S&&to[i]!=T&&!vis[to[i]])
{
vis[to[i]]=1;
q.push(to[i]);
}
if(!ex[u]) return 0;
}
}
return 1;
}
void relabel(int u)
{
ht[u]=INF;
for(int i=head[u];i!=-1;i=nxt[i])
{
if(val[i]) ht[u]=min(ht[u],ht[to[i]]);
}
++ht[u];
}
int hlpp()
{
if(!bfs()) return 0;
ht[S]=n;
memset(gap,0,sizeof(gap));
for(int i=1;i<=n;++i)
{
if(ht[i]!=INF) ++gap[ht[i]];
}
for(int i=head[S];i!=-1;i=nxt[i])
{
if(val[i])
{
int tmp=val[i];
ex[S]-=tmp;
ex[to[i]]+=tmp;
val[i]-=tmp;
val[i^1]+=tmp;
if(to[i]!=S&&to[i]!=T&&!vis[to[i]])
{
vis[to[i]]=1;
q.push(to[i]);
}
}
}
while(!q.empty())
{
int u=q.top();
q.pop();vis[u]=0;
while(push(u))
{
if(!--gap[ht[u]])
{
for(int i=1;i<=n;++i)
{
if(i!=S&&i!=T&&ht[i]>ht[u]&&ht[i]<n+1) ht[i]=n+1;
}
}
relabel(u);
++gap[ht[u]];
}
}
return ex[T];
}
int main()
{
n=read();m=read();S=read();T=read();
head.resize(n+1,-1);
for(int i=1;i<=m;++i)
{
int u=read(),v=read(),w=read();
//printf("__%d %d %d\n",u,v,w);
join(u,v,w);
join(v,u,0);
}
printf("%d",hlpp());
return 0;
}