最大流
EK算法:
在残余网络中不断寻找增广路径(使用bfs)直到不能再增广,并把每次找到的增广路径的流量加起来就是最大流。
#include<iostream>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<cstring>
#include<algorithm>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define fori(x,s,t) for(int x=s;x<=t;x++)
#define ford(x,s,t) for(int x=s;x>=t;x--)
#define ll long long
using namespace std;
const int M=1e4+10,inf=1e8;
struct N
{
int v,c,re;
};
vector<N> g[M];
int pre[M],pe[M],flow[M],n,m;
int bfs(int s,int t) //bfs寻找增广路径
{
memset(pre,-1,sizeof(pre));
pre[s]=0;
flow[s]=inf;
queue<int> q;
q.push(s);
while(!q.empty())
{
int p=q.front();q.pop();
if(p==t)break;
for(int i=0,j=g[p].size();i<j;i++)
{
if(g[p][i].c<=0||pre[g[p][i].v]!=-1)continue;
flow[g[p][i].v]=min(g[p][i].c,flow[p]);
pre[g[p][i].v]=p;
pe[g[p][i].v]=i;
q.push(g[p][i].v);
}
}
if(pre[t]==-1)return -1; //找不到增广路径,返回-1
return flow[t]; //找到增广路径,返回增广路径的流量
}
int ek(int s,int t)
{
int ans=0,da;
while(1)
{
da=bfs(s,t); //寻找增广路径
if(da<=0)break;//找不到增广路径,结束
int p=t;
while(p!=s) //找到增广路径,更新残余网络
{
N &tem=g[pre[p]][pe[p]];
tem.c-=da;
g[p][tem.re].c+=da;
p=pre[p];
}
ans+=da;
}
return ans;
}
void add(int x,int y,int z)//加边
{
g[x].push_back((N){y,z,g[y].size()});
g[y].push_back((N){x,0,g[x].size()-1});
}
int main()
{
int s,t,u,v,c;
scanf("%d%d%d%d",&n,&m,&s,&t);
while(m--)
{
scanf("%d%d%d",&u,&v,&c);
add(u,v,c);
}
printf("%d\n",ek(s,t));
return 0;
}
dinic算法:
和EK算法属于同类型的最大流算法,都是通过寻找增广路径来求最大流的。
与EK算法不同的是,dinic算法先使用bfs将图进行分层,然后在分层图上使用dfs寻找增广路径。
#include<iostream>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<cstring>
#include<algorithm>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define fori(x,s,t) for(int x=s;x<=t;x++)
#define ford(x,s,t) for(int x=s;x>=t;x--)
#define ll long long
using namespace std;
const int M=1e4+30,inf=1e8;
struct N
{
int v,c,rv;
};
vector<N> g[M];
int n,m,dep[M],now[M];
bool bfs(int s,int t) //将图分层,dep记录每个顶点的层数(层数从0或1开始都是没问题的)
{
memset(dep,-1,sizeof(dep));
dep[s]=0;
queue<int> q;
q.push(s);
while(!q.empty())
{
int p=q.front();q.pop();
for(int i=0,j=g[p].size();i<j;i++)
{
int u=g[p][i].v,c=g[p][i].c;
if(c<=0||dep[u]!=-1)continue; //如果边的容量已经小于等于0了,那么就不能再对其指向的顶点分层
dep[u]=dep[p]+1;
q.push(u);
}
}
memset(now,0,sizeof(now));
return dep[t]!=-1; //返回从s到t是否可以分层
}
ll dfs(int s,int t,ll f) //寻找增广路径
{
if(s==t)return f; //递归出口,当dfs到t的时候则说明找到了s到t的增广路径,返回增广路径的流量
for(int i=now[s],j=g[s].size();i<j;i++)
{
now[s]=i; //当前弧优化
int u=g[s][i].v,c=g[s][i].c,ru=g[s][i].rv;
if(c<=0||dep[u]!=dep[s]+1)continue;
ll tem=dfs(u,t,min(f,(ll)c)); //递归寻找u,到t的增广路径
if(tem>0) //找到增广路径,更新网络
{
g[s][i].c-=tem;
g[u][ru].c+=tem;
return tem;
}
}
return 0;
}
ll dinic(int s,int t)
{
ll ans=0,tem;
while(bfs(s,t)) //对图进行分层,若不能分层,那么就不存在s到t 的增光路径,结束
while((tem=dfs(s,t,inf))>0)ans+=tem; //在分层图中寻找增广路径
return ans;
}
void add(int x,int y,int z) //加边
{
g[x].push_back((N){y,z,g[y].size()});
g[y].push_back((N){x,0,g[x].size()-1});
}
int main()
{
int s,t;
scanf("%d%d%d%d",&n,&m,&s,&t);
int x,y,z;
while(m--)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
printf("%lld\n",dinic(s,t));
return 0;
}
1204

被折叠的 条评论
为什么被折叠?



