YunYan

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

dicnic算法求最大流。

dicnic算法就像是对F-F算法的一个优化,F-F算法是无脑求增广路径,直到求不出来路径为止。

 

 

 比如说这个图,求从1~4的最大流量,很显然应该是200,路径1--2--4和路径1--3--4。但是如果FF算法第一次走的路径是1--2--3--4,那么这条路径的流量就变成了1,然后根据FF算法的步骤,下一步建反向边再跑图,比如说走的是1--3--2--4

然后再建返向边再跑。。。。一直把1--2和1--3这两条边的流量跑完为止。这样算法的性能一下就下去了,而dicnic算法刚好解决了这个问题。

首先对残余网络进行分层,用一个数组dis记录一下,比如说dis[]...dis[1]=0,dis[2]=dis[3]=1,dis[4]=2。在dfs寻找增广路的时候,只能一层接着一层的寻找,可以想象成一个楼梯,源点在最低层,汇点在最高层,从最底层向最高层走,那么相同层之间走就没有了什么意义了。

简而言之,dicnic算法就是先对当前网络进行分层,然后再从分层的基础上寻找增广路径,直到找不到增广路径,再更新网络分层

记一个洛谷的简单的板子题

code:

#include<bits/stdc++.h>
using namespace std;
const int N=120000+120000+7;
const long long  INF=1e18+7;
class stu{
    public:
        int to,nxt;
        long long val;
}edge[N];
int n,m,s,t;
int flag[1200+1][1200+1];
long long  dis[N];
int tol=0;
int head[N];
void add(int x,int y,long long  z){
    edge[tol].to=y;
    edge[tol].val=z;
    edge[tol].nxt=head[x];
    head[x]=tol++;
}
bool bfs(int s,int t){
    for(int i=0;i<=n;i++) dis[i]=INF;
    queue<int>que;
    dis[s]=0;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            long long w=edge[i].val;
            if(w>0&&dis[u]+1<dis[v]) {
                dis[v]=dis[u]+1;
                que.push(v);
            }
        }
    }
    return dis[t]!=INF;
}
int dfs(int s,int t,long long  mn){
    if(s==t) return mn;
    for(int i=head[s];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        long long w=edge[i].val;
        if(w<=0||dis[v]!=dis[s]+1) continue ;
        int cw=dfs(v,t,min(w,mn));
        if(cw>0){
            edge[i].val-=cw;
            edge[i^1].val+=cw;
            return cw;
        }
    }
    return 0;
}
void dicnic(int s,int t){
    long long  ans=0;
    while(bfs(s,t)){
        int d;
        while(d=dfs(s,t,INF)){
            ans+=d;
        }
    }
    printf("%lld",ans);
}
     
int main(){
    memset(head,-1,sizeof head); 
    scanf("%d%d%d%d",&n,&m,&s,&t);
    int x,y;
    long long z;
    for(int i=1;i<=m;i++){
        scanf("%d%d%lld",&x,&y,&z);
        if(!flag[x][y]){
            add(x,y,z);
            flag[x][y]=tol;
            add(y,x,0);
        }
        else  edge[flag[x][y]-1].val+=z;
    }
    dicnic(s,t);
    return 0;
} 

 dinic算法的当前弧优化:

  当前弧优化是在dfs寻找增广路径的时候加的一个优化。假如说某一个点s个3个子节点,那么就对应3条有向边,编号分别为1,2,3。在dfs的寻路的过程按顺序依次遍历1,2,3,假如说从第一次找到的从S---T的路径为从二号边往下的路径,即1号边不能到达T,这时我们就记录一下2号边,当再次寻路的时候直接从2号边开始寻找就行了,没必要再找一遍1号边了。这种优化成为当前弧优化。

实现起来也比较简单:

 

#include<bits/stdc++.h>
using namespace std;
const int N=120000+120000+7;
const long long  INF=1e18+7;
int cur[N];
class stu{
    public:
        int to,nxt;
        long long val;
}edge[N];
int n,m,s,t;
int flag[1200+1][1200+1];
long long  dis[N];
int tol=0;
int head[N];
void add(int x,int y,long long  z){
    edge[tol].to=y;
    edge[tol].val=z;
    edge[tol].nxt=head[x];
    head[x]=tol++;
}
bool bfs(int s,int t){
    for(int i=0;i<=n;i++) dis[i]=INF;
    queue<int>que;
    dis[s]=0;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            long long w=edge[i].val;
            if(w>0&&dis[u]+1<dis[v]) {
                dis[v]=dis[u]+1;
                que.push(v);
                if(v==t) return dis[t]!=INF;
            }
        }
    }
    return dis[t]!=INF;
}
int dfs(int s,int t,long long  mn){
    if(s==t) return mn;
    for(int i=cur[s];i!=-1;i=edge[i].nxt){
        cur[s]=i;
        int v=edge[i].to;
        long long w=edge[i].val;
        if(w<=0||dis[v]!=dis[s]+1) continue ;
        int cw=dfs(v,t,min(w,mn));
        if(cw>0){
            edge[i].val-=cw;
            edge[i^1].val+=cw;
            return cw;
        }
    }
    return 0;
}
void dicnic(int s,int t){
    long long  ans=0;
    while(bfs(s,t)){
        for(int i=1;i<=n;i++){
            cur[i]=head[i];
        }
        int d;
        while(d=dfs(s,t,INF)){
            ans+=d;
        }
    }
    printf("%lld",ans);
}
int main(){
    memset(head,-1,sizeof head); 
    scanf("%d%d%d%d",&n,&m,&s,&t);
    int x,y;
    long long z;
    for(int i=1;i<=m;i++){
        scanf("%d%d%lld",&x,&y,&z);
        if(!flag[x][y]){
            add(x,y,z);
            flag[x][y]=tol;
            add(y,x,0);
        }
        else  edge[flag[x][y]-1].val+=z;
    }
    dicnic(s,t);
    return 0;
} 

 

posted on 2020-07-17 21:56  Target--fly  阅读(279)  评论(0编辑  收藏  举报