萌新一枚,借鉴了许多大佬而总结下的笔记,可能有瑕疵或者错误,望指正。
1主要用于求网络最大流问题
思路
1存储图,每条边可以看成一个水管,有容量和流量,流量不能超过容量
循环:
2构造层次网络(level gragh)和残留网络(还有多少水可以流,容量减流量)
3寻找到一个阻塞流,就是不能流更多的水的路径,(最大流是阻塞流,阻塞流不是最大流)
4如果到达不了终点,循环就结束了
5更新残留网络,正向流量加相应的值,答案加相应的值,反向路径的流量减去相应的值(这意味着残留网络中他的权值变大,变化大小为当前线路最细的水管能流的流量)。
代码实现:
1图的存储
struct edge{
int to,nx,cap,flow;//链式前项星存图
//cap为容量,flow为流量
}e[maxn<<1];
int tot=1;
int head[maxn];
int ans;//记录最大流
int cur[maxn];//暂时保存head
inline void add(int u,int v,int w)//添加边
{
e[++tot].to=v;e[tot].cap=w;
e[tot].flow=0;e[tot].nx=head[u];
head[u]=tot;//容量为w,流量为0
e[++tot].to=u;e[tot].cap=0;
e[tot].flow=0;e[tot].nx=head[v];
head[v]=tot;//容量为0,流量为0的反向边,
}
int dep[maxn];//存储level gragh,从起点走几步能到该点,不允许dep从大到小的路径,以及dep相同的路径
2寻找阻塞流
bool bfs(int s,int t)//寻找阻塞流,就是当前不能再添加流量的路线,最大流一定是阻塞流,阻塞流不一定是最大流
{
queue<int>q;
memset(dep,-1,sizeof(dep));
dep[s]=0;
q.push(s);
while(!q.empty())
{
int p=q.front();
q.pop();
for(int i=head[p];i;i=e[i].nx)
{
int to=e[i].to;
if(e[i].cap>e[i].flow&&dep[to]==-1)
{
dep[to]=dep[p]+1;//记录level,也可以说到这要多少步
q.push(to);
}
}
}
for(int i=1;i<=n;i++)//初始化cur
cur[i]=head[i];
return dep[t]!=-1;
}
3根据相应的阻塞流更新
int dinic(int u,int t,int flow)
{
if(u==t)//如果找到终点,最大流加上flow,并且向上返回更新相关线路的流量
return flow;
int sum=0;
for(int &i=cur[u];i;i=e[i].nx)//在遍历过程中cur会不断变化成当前边的编号
{
int to=e[i].to;
if(dep[to]==dep[u]+1&&e[i].cap>e[i].flow)//如果道路符合条件
{
int up=dinic(to,t,min(flow-sum,e[i].cap-e[i].flow));//如果找到终点,up为更新的值
if(up>0)//如果不为0,那么就是找到了
{
e[i].flow+=up;//正向边流量加up,容量不变
e[i^1].flow-=up;//反向边流量减去up,容量不变
sum+=up;
}
}
}
return sum;
}
4主函数实际应用
int main()
{
int n,m;
cin>>n>>m;//n个点,m个有向边
int s,t;
cin>>s>>t;//s为起点
for(int i=1;i<=m;i++)
{
int x,y,v;
cin>>x>>y>>v;//x为起点,y为终点,v为权值
add(x,y,v);
}
while(bfs(s,t))//当找不到阻塞流时,结束
{
ans+=dinic(s,t,inf);
}
cout<<ans;
return 0;
}