1.什么是网络最大流
形象的来说,网络最大流其实就是这样一个生活化的问题:现在有一个由许多水管组成的水流系统,每一根管道都有自己的最大通过水流限制(流量),超过这个限制水管会爆(你麻麻就会来找你喝茶qwq)。现在,给定你一个出水口(原点),一个出水口(汇点),求这个网络中水流量的最大值。
????看起来很简单对不对?在我们看起来的确是这样的,而这部分的难点也确实不在思路上,而是在于算法设计以及代码实现上。
2.怎么求解网络最大流
首先想明白一件事情,对于一个节点来说,他接受的流量一定小于等于他给出的流量之和,否则,水管一定会爆掉。而对于一个节点来说,他接受的流量有可能大于任意一个他出边的流量,因为这个节点可以把接受流给出到不同的水管上,进而实现分流。
有了这两点,思路就很清晰了(贪心算):
1.首先,我们需要寻找一条可行的流量方案(此时,不一定为最大流量)。
2.然后我们依次扩展这条路径上的所有节点,看看这个节点是否还可以接受流量,直到已经满流。
3.重复上述步骤,直到没有可行流动路径。
4.此时我们累加的流量即为网络最大流,我们把这种方法称为最大流Dinic算法
3.实现细节
这种算法看起来简单,实际上实现起来会遇到许多小毛病,以及许多很难理解的代码实现,这里举一个栗子
在步骤2的时候我们采用dfs进行扩展,也称为网络最大流的扩展部分算法,需要借助到反边这样一个概念,即:两个节点A,B间有一条权值为w无向边。我们就把他拆分成一条由A指向B的有向边与一条由B指向A的有向边,其中,这两条边的权值之和为w,这样一来一回,两者相互抵消巧妙的实现了回溯
上代码:qwq
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 1000005
#define M 4*1000005
#define INF 0xfffffff
using namespace std;
int Read()//快读
{
int num=0,k=1;
char c=getchar();
while(c!='-'&&(c<'0'||c>'9')) c=getchar();
if(c=='-')
{
k=-1;
c=getchar();
}
while(c<='9'&&c>='0')
{
num=(num<<3)+(num<<1)+c-'0';
c=getchar();
}
return num*k;
}
struct node
{
int from;
int to;
int v;
int next;
};
node edge[2*M];
int cnt_edge=1,n,m,s,t;
long long ans=0;
int last[N],deep[N];
void add_edge(int u,int v,int w)
{
edge[++cnt_edge].from=u;
edge[cnt_edge].to=v;
edge[cnt_edge].v=w;
edge[cnt_edge].next=last[u];
last[u]=cnt_edge;
}
bool bfs() //判断是否有通路
{
memset(deep,-1,sizeof(deep));
deep[s]=0;
queue<int >q;
q.push(s);
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=last[now];i;i=edge[i].next)
{
int j=edge[i].to;
if(deep[j]==-1&&edge[i].v)
{
deep[j]=deep[now]+1;
q.push(j);
}
}
}
return deep[t]!=-1;
}
int dfs(int now,int flow) //flow为当前流量
{
if(now==t) return flow;
int delta=flow; //delta是剩余流量,就是流不下去的流量
for(int i=last[now];i;i=edge[i].next)
{
int to=edge[i].to;
if((deep[to]==(deep[now]+1))&&edge[i].v > 0)
{
int d=dfs(to,min(delta,edge[i].v));
if(!d) deep[to] = 1e9; //剪枝优化,当前点无法下流
edge[i].v-=d;edge[i^1].v+=d;delta-=d;//流下去,反边+d,方便回流
if(!delta) break;
}
}
return flow-delta; //返回这里留下去了多少 ,即当前点的最大流量
}
int main ()
{
n=Read();m=Read();s=Read();t=Read();
int u,v,w;
for(int i=1;i<=m;i++)
{
u=Read();v=Read();w=Read();
add_edge(u,v,w);add_edge(v,u,0);
}
while(bfs()) ans+=dfs(s,INF);
printf("%lld
",ans);
return 0;
}
看完关注哦~