根据定义,若一条从源点S到汇点T的路径上各点的剩余容量都大于0,则称这条路径为增广路。那么就可以通过不断寻找增广路来求出最大流。
具体做法就是通过bfs寻找从S到T的增广路径,并顺便计算出最小剩余容量minx,找到后路径上各点减去minx,答案(最大流)加上minx。
需要注意的是,因为是单纯的遍历所有剩余流量大于零的边,所以无法保证当前所选的边是否是最优,所以需要一种方法可以“后悔”,即撤回之前的决定,而这种“后悔”的方法就是退流,即在遍历时除了考虑当前遍历的边以外,还需要考虑每条边的反向边。
具体实现时,我们按照邻接表成对储存技巧,在存储边时下标从2开始,那么反向边和边之间可以通过xor 1来转换。
代码如下
#include
using namespace std;
int n,m,S,T,linkk[205],t=1;
int q[505],head,tail;
int before[205],minx[205];
long long ans=0;
struct node{
int y,v,n;
}e[405];
bool vis[205];
inline int read(){
int NUM=0,f=1;
char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())
NUM=(NUM<<1)+(NUM<<3)+c-48;
return NUM*f;
}//快读
void insert(int xx,int yy,int zz){
e[++t].y=yy;
e[t].v=zz;
e[t].n=linkk[xx];
linkk[xx]=t;
e[++t].y=xx;
e[t].v=0;
e[t].n=linkk[yy];
linkk[yy]=t;
return;
}//正反存边
void init(){
n=read();m=read();S=read();T=read();
for(int i=1;i<=n;++i){
int x,y,z;
x=read();y=read();z=read();
insert(x,y,z);
}
return;
}
void Up(){
int now=m;
while(now!=S){
int i=before[now];
e[i].v-=minx[m];
e[i^1].v+=minx[m];
now=e[i^1].y;
}
ans+=minx[m];
return;
}
bool BFS(){
memset(vis,0,sizeof(vis));
head=1;tail=0;
q[++tail]=S;
vis[S]=1;
minx[S]=1e9;
for(;head<=tail;++head){
int x=q[head];
for(int i=linkk[x];i;i=e[i].n){
if(!e[i].v)continue;
int y=e[i].y;
if(vis[y])continue;
vis[y]=1;
minx[y]=min(minx[x],e[i].v);//更新最小剩余容量
q[++tail]=y;
before[y]=i;
if(y==T) return 1;//遍历到终点,找到一条路径
}
}
return 0;
}
void work(){
while(BFS())Up();
cout<return;
}
int main(){
init();
work();
return 0;
}
由于Edmonds-Karp每次可能遍历整个残量网络,但只找出一条增广路,明显有很大的优化空间,所以就有了dinic。
与EK只能往父亲反不同,dinic是基于分层图的DFS,一次可以求出多条增广路,同时加入若干剪枝,一般能够处理10^4~10^5的网络。
代码:
#include
using namespace std;
const int MAXN=1e9;
int n,m,linkk[1005],t=1;
int q[2005],head,tail;
int dis[2005];
long long ans=0;
struct node{
int y,v,n;
}e[1000005];
inline int read(){
int NUM=0,f=1;
char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())
NUM=(NUM<<1)+(NUM<<3)+c-48;
return NUM*f;
}
void insert(int xx,int yy,int zz){
e[++t].y=yy;e[t].v=zz;e[t].n=linkk[xx];linkk[xx]=t;
e[++t].y=xx;e[t].v=0;e[t].n=linkk[yy];linkk[yy]=t;
return;
}
void init(){
n=read();m=read();
for(int i=1;i<=n;++i){
int x,y,z;
x=read();y=read();z=read();
insert(x,y,z);
}
return;
}
int dinic(int x,int flow,int fa){
if(x==m)return flow;
int rest=flow,k;
for(int i=linkk[x];i&&rest;i=e[i].n){
int y=e[i].y;
if(e[i].v&&dis[y]==dis[x]+1){
k=dinic(y,min(e[i].v,rest));
if(!k)dis[y]=0;
e[i].v-=k;
e[i^1].v+=k;
rest-=k;
}
}
return flow-rest;
}
bool BFS(){
memset(dis,0,sizeof(dis));
head=1;tail=0;
q[++tail]=1;
dis[1]=1;
for(;head<=tail;++head){
int x=q[head];
for(int i=linkk[x];i;i=e[i].n){
if(e[i].v&&!dis[e[i].y]){
dis[e[i].y]=dis[x]+1;
q[++tail]=e[i].y;
if(e[i].y==m) return 1;
}
}
}
return 0;
}
void work(){
int flow=0;
while(BFS())
while(flow=dinic(1,MAXN,0))
ans+=flow;
cout<return;
}
int main(){
init();
work();
return 0;
}