网络流三种算法及比较

核心代码
(1)EK 算法
复杂度O(V*E*E)

#define N 204  
int c[N][N];//边容量  
int f[N][N];//边实际流量  
int pre[N];//记录增广路径  
int res[N];//残余网络  
queue<int> qq;  
void init(){  
    while(!qq.empty())qq.pop();  
    memset(c,0,sizeof(c));  
    memset(f,0,sizeof(f));  
}  
int EK(int s,int t){  
    int i,j;  
    int ans=0;  
    while(1){  
        memset(res,0,sizeof(res));  
        res[s] = MAX;//源点的残留网络要置为无限大!否则下面找增广路出错  
        pre[s] = -1;  
        qq.push(s);  
        //bfs找增广路径  
        while(!qq.empty()){  
            int x = qq.front();  
            qq.pop();  
            for(i=1;i<=t;i++){  
                if(!res[i] && f[x][i] < c[x][i]){  
                    qq.push(i);  
                    pre[i] = x;  
                    res[i] = min(c[x][i] - f[x][i], res[x]);//这里类似dp,如果有增广路,那么res[t]就是增广路的最小权  
                }  
            }  
        }  
        if(res[t]==0)break;//找不到增广路就退出  
        int k = t;  
        while(pre[k]!=-1){  
            f[pre[k]][k] += res[t];//正向边加上新的流量  
            f[k][pre[k]] -= res[t];//反向边要减去新的流量,反向边的作用是给程序一个后悔的机会  
            k = pre[k];  
        }  
        ans += res[t];  
    }  
    return ans;  
}  

(2)Dinic递归

#define M 400   
struct node {  
    int u, v, next, cap;  
} edge[M*M];  
int next[M], head[M], layer[M], Q[M * 2], mark[M];  
int ecnt;  
void init(){  
    ecnt= 0;  
    memset(head,-1,sizeof(head));  
}  
void add(int u, int v, int c) {  
    edge[ecnt].u = u;  
    edge[ecnt].v = v;  
    edge[ecnt].cap = c;  
    edge[ecnt].next = head[u];  
    head[u] = ecnt++;  
    edge[ecnt].u = v;  
    edge[ecnt].v = u;  
    edge[ecnt].cap = 0;  
    edge[ecnt].next = head[v];  
    head[v] = ecnt++;  
}  
bool BFS(int begin, int end) {  
    int i, l, h, k, y;  
    for (i = 0; i <= end; i++) layer[i] = -1;  
    layer[begin] = 0;  
    l = h = 0;  
    Q[l++] = begin;  
    while (h < l) {  
        k = Q[h++];  
        for (i = head[k]; i != -1; i = edge[i].next) {  
            y = edge[i].v;  
            if (edge[i].cap > 0 && layer[y] == -1) {  
                layer[y] = layer[k] + 1;  
                if (y == end)  
                    return true;  
                Q[l++] = y;  
            }  
        }  
    }  
    return false;  
}  

int DFS(int x, int exp, int end) {  
    mark[x] = 1;  
    if (x == end)return exp;  
    int y, temp, i;  
    for (i = next[x]; i != -1; i = edge[i].next, next[x] = i) {  
        y = edge[i].v;  
        if (edge[i].cap > 0 && layer[y] == layer[x] + 1 && !mark[y]) {  
            if ((temp = (DFS(y, min(exp, edge[i].cap), end))) > 0) {  
                edge[i].cap -= temp;//流完后正向流表示剩余流量  
                edge[i^1].cap += temp;//流完后反向流表示正向流的流量  
                return temp;  
            }  
        }  
    }  
    return 0;  
}  

int Dinic_flow(int begin, int end) {  
    int i, ans = 0, flow;  
    while (BFS(begin, end)) {  
        for (i = 0; i <= end; i++)next[i] = head[i];  
        while (true) {  
            for (i = 0; i <= end; i++) mark[i] = 0;  
            flow = DFS(begin, INT_MAX, end);  
            if (flow == 0)break;  
            ans += flow;  
        }  
    }  
    return ans;  
}  

(3)SAP算法

const int MAXN=20010;
const int MAXM=500010;
int n,m;//n为点数 m为边数
int h[MAXN];
int gap[MAXN];
 int p[MAXN],ecnt;
int source,sink;
struct edge{
    int v;//边的下一点
    int next;//下一条边的编号
    int val;//边权值
}e[MAXM];
inline void init(){memset(p,-1,sizeof(p));eid=0; 
//有向
inline void insert1(int from,int to,int val){
    e[ecnt].v=to;
    e[ecnt].val=val;
    e[ecnt].next=p[from];
    p[from]=eid++;
    swap(from,to);
    e[ecnt].v=to;
    e[ecnt].val=0;
    e[ecnt].next=p[from];
    p[from]=eid++;
} 
//无向
inline void insert2(int from,int to,int val){
    e[ecnt].v=to;
    e[ecnt].val=val;
    e[ecnt].next=p[from];
    p[from]=eid++;
    swap(from,to);
    e[ecnt].v=to;
    e[ecnt].val=val;
    e[ecnt].next=p[from];
    p[from]=eid++;
}
inline int dfs(int pos,int cost){
    if (pos==sink){
        return cost;
    }
    int j,minh=n-1,lv=cost,d;
    for (j=p[pos];j!=-1;j=e[j].next){
        int v=e[j].v,val=e[j].val;
        if(val>0){
            if (h[v]+1==h[pos]){
                if (lv<e[j].val) d=lv;
                else d=e[j].val;
                d=dfs(v,d);
                e[j].val-=d;
                e[j^1].val+=d;
                lv-=d;
                if (h[source]>=n) return cost-lv;
                if (lv==0) break;
            }

            if (h[v]<minh)  minh=h[v];
        }
    }
    if (lv==cost){
        --gap[h[pos]];
        if (gap[h[pos]]==0) h[source]=n;
        h[pos]=minh+1;
        ++gap[h[pos]];
    }
    return cost-lv;
}
int sap(int st,int ed){

    source=st;
    sink=ed;
    int ans=0;
    memset(gap,0,sizeof(gap));
    memset(h,0,sizeof(h)); 
    gap[st]=n;
    while (h[st]<n){
        ans+=dfs(st,INT_MAX);
    }
    return ans;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值