<svg style="display: none;" xmlns="http://www.w3.org/2000/svg"> </svg>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#define maxn 10010
#define maxm 100010
#define inf 0x7fffffff
using namespace std;
int n,m,s,t;
int sum,ans;
int d[maxn];
struct edge{
int to,val,rev; //rev表示反边在to的vector当中下标是几
edge (int _to,int _val,int _rev) //构造函数
{
to=_to;
val=_val;
rev=_rev;
}
};
vector<edge> e[maxn];
void addedge(int x,int y,int w)
{
e[x].push_back(edge(y,w,e[y].size()));
e[y].push_back(edge(x,0,e[x].size()-1));
/* 或者 也可以这样写 e[x].push_back((edge){y,w,e[y].size()}); e[y].push_back((edge){x,0,e[x].size()-1}); 这样写不需要👆的构造函数 */
}
bool bfs()
{
memset(d, -1, sizeof(d));
queue<int> q;
q.push(s);
d[s]=0;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=0;i<e[x].size();i++)
{
int y=e[x][i].to;
if(d[y]==-1 && e[x][i].val)
{
q.push(y);
d[y]=d[x]+1;
}
}
}
if(d[t]==-1)
return 0;
else
return 1;
}
int dfs(int x,int low) //x表示当前节点,low表示当前流到x的残量
{
if(x==t || low==0)
return low;
int totflow=0; //totflow表示x节点总共流出的流量
for(int i=0;i<e[x].size();i++)
{
int y=e[x][i].to;
int rev=e[x][i].rev;
if(d[y]==d[x]+1 && e[x][i].val) //y是x的下一层 且 当前边有残量>0
{
int a=dfs(y,min(low,e[x][i].val)); //a表示当前边流出的流量
e[x][i].val-=a;
e[y][rev].val+=a;
low-=a;
totflow+=a;
if(low==0) //流到x的流量流完了
return totflow;
}
}
if(low!=0) //优化,直观理解:流到x的流量会有冗余,这一轮dfs中就再也不到x了
d[x]=-1;
return totflow;
}
void dinic()
{
while(bfs())
ans+=dfs(s,inf);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
addedge(x, y, w);
}
dinic();
printf("%d\n",ans);
return 0;
}