网络最大流(EK算法)
Whiteying
2018-10-16 17:59:31
网络流EK算法主要是以bfs为主,寻找一条增广路。
增广路算法的关键是 寻找增广路 和 改进网络流。
1. bfs判断由从源点到汇点是否联通,并寻找到这条增广路;
2. 更新路径上的流量,正向边减去流量,反向弧加上流量;
3. 重复执行1过程,直到找不到增广路。
~~不懂是吗,其实我也不懂为啥要加反向边~~
创建反向弧是因为在其他增广路要经过这条路径时,要将此路径上的流量反推过去,实现流量最大化。
emmm,我知道其实自己说的很绕。。。
但是多读读下面的模板代码应该就能理解,毕竟我又不擅长写那种难以读懂的代码。
邻接矩阵实现
```cpp
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define ms(n,x) memset(n,x,sizeof(n))
using namespace std;
const int MAXN = 300;
const int MAX_INT = ((1 << 30) - 1);
int s,t;
int n,m;
bool vis[MAXN];
int pre[MAXN];
int mp[MAXN][MAXN];
bool bfs(int s,int t)
{
queue <int> que;
ms(vis,0);
ms(pre,-1);
que.push(s);
vis[s]=true;
pre[s]=s;
while(!que.empty())
{
int u=que.front();
que.pop();
for(int i=1;i<=n;i++)
{
if(mp[u][i]&&!vis[i])
{
vis[i]=true;
pre[i]=u;
if(i==t)
return true;
que.push(i);
}
}
}
return false;
}
int EK()
{
int ans=0;
while(bfs(s,t))
{
int mi=MAX_INT;
for(int i=t;i!=s;i=pre[i])
{
mi=min(mi,mp[pre[i]][i]);
}
for(int i=t;i!=s;i=pre[i])
{
mp[pre[i]][i]-=mi;
mp[i][pre[i]]+=mi;
}
ans+=mi;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%d%d",&s,&t);
ms(mp,0);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
mp[x][y]=z;
}
printf("%d\n",EK());
return 0;
}
/*
6 7
1 6
1 2 2
1 3 1
3 4 1
2 5 1
2 4 2
4 6 2
5 6 1
*/
```
邻接表实现
```cpp
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define ms(n,x) memset(n,x,sizeof(n))
using namespace std;
struct Edge
{
int to,next,weigh;
};
struct Node
{
int from,id;
};
const int MAXN = 10005;
const int MAXM = 100005*2;
const int MAX_INT = (1<<30);
Edge edge[MAXM];
Node pre[MAXM];
int head[MAXM];
bool vis[MAXM];
int n,m,s,t,cont;
void init()
{
cont=0;
ms(edge,0);
ms(head,-1);
}
void addedge(int from,int to,int weigh)
{
edge[cont].to=to;
edge[cont].weigh=weigh;
edge[cont].next=head[from];
head[from]=cont++;
}
bool bfs(int s,int t)
{
queue<int> que;
ms(pre,-1);
ms(vis,0);
pre[s].from=s;
vis[s]=true;
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
for(int i=head[u];i+1;i=edge[i].next)
{
int from=edge[i].to;
if(!vis[from]&&edge[i].weigh)
{
pre[from].from=u;
vis[from]=true;
pre[from].id=i;
if(from==t)
return true;
que.push(from);
}
}
}
return false;
}
int EK()
{
int ans=0;
while(bfs(s,t))
{
int mi=MAX_INT;
for(int i=t;i!=s;i=pre[i].from)
{
mi=min(mi,edge[pre[i].id].weigh);
}
for(int i=t;i!=s;i=pre[i].from)
{
edge[pre[i].id].weigh-=mi;
edge[pre[i].id^1].weigh+=mi;
}
ans += mi;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%d%d",&s,&t);
init();
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,0);
}
printf("%d\n",EK());
return 0;
}
```
模板由此理解:
https://blog.csdn.net/txl199106/article/details/64441994