网络流的相关定义:
源点:有n个点,有m条有向边,有一个点很特殊,只出不进,叫做源点。
汇点:另一个点也很特殊,只进不出,叫做汇点。
容量和流量:每条有向边上有两个量,容量和流量,从i到j的容量通常用c[i,j]表示,流量则通常是f[i,j].
通常可以把这些边想象成道路,流量就是这条道路的车流量,容量就是道路可承受的最大的车流量。很显然的,流量<=容量。而对于每个不是源点和汇点的点来说,可以类比的想象成没有存储功能的货物的中转站,所有“进入”他们的流量和等于所有从他本身“出去”的流量。
最大流:把源点比作工厂的话,问题就是求从工厂最大可以发出多少货物,是不至于超过道路的容量限制,也就是,最大流。
思想:起初最大流ans=0,每次找一条从汇到源的路,找到这条路的最小的流量minn,累加到最大流ans,这条路的每一段流量减去minn,同时反向边加上minn。
参考文章.
参考.
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,s,t;
ll mp[205][205]={{0}}; //两点之间流量
int father[205]={0}; //用于遍历一条路
int vis[205]={0}; //标记
ll ans = 0; //最大流
ll minn[205]; //一条路最小的流量
vector<int> e[205]; //邻接矩阵
int bfs(){
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(s);
vis[s]=1;
minn[s] = 1e9;
while(!q.empty()){
int u = q.front();
q.pop();
for(int i = 0; i < e[u].size(); i++){
int v = e[u][i];
if(mp[u][v]==0 || vis[v]) continue;
minn[v]=min(minn[u],mp[u][v]); //源到v最小流量=min(源到u,u到v)
father[v]=u;
vis[v]=1;
q.push(v);
if(v==t) return 1; //存在从源到汇 true
}
}
return 0; //不存在 false
}
void update(){
int u = t;
while(u!=s){
int v = father[u];
mp[u][v]+=minn[t]; //反向边加
mp[v][u]-=minn[t]; //正向边减
u=v;
}
ans+=minn[t];
}
int main(){
cin>>n>>m>>s>>t;
int flag[205][205]={{0}}; //处理重边
while(m--){
int u,v,w;
cin>>u>>v>>w;
if(flag[u][v]==0){
e[u].push_back(v);
e[v].push_back(u);
}
mp[u][v]+=w; //处理重边
}
while(bfs()) update();
cout<<ans<<endl;
return 0;
}