网络流-EK算法

EK算法的思路:
基于贪心的思想,每次选取一条起点到终点的路径,毋庸置疑,这条路的流量就等于这条路径上的权值是最小值。将这条路的权值都减去流量,再将路径的反向边加上流量(这样可以就给贪心一次反悔的机会),无限循环以上步骤,到找不到任何一条起点到终点的路,最后所有的最小值加起来就是最大流了。
(这只是我对EK算法的总结,学习网络流还是去看别人的博客吧)
代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#define LL long long
#define Max 100005
const LL mod=1e9+7;
const LL LL_MAX=9223372036854775807;
using namespace std;
struct node
{
    int v,next;
    LL w;
}edge[Max];//使用邻接表存边
int n,m;
int pre[Max],head[Max],rec[Max];//pre保存路径,rec保存该点在邻接表中的位置,head邻接表的指针
LL flow[Max];//记录最小值
int no;
queue<int>q;
void init()
{
   no=0;
   memset(head,-1,sizeof(head));
}
void add(int u,int v,LL c){
    edge[no].v=v,edge[no].w=c;
    edge[no].next=head[u],head[u]=no++;

    edge[no].v=u;edge[no].w=0;
    edge[no].next=head[v],head[v]=no++;
}

LL bfs(int st,int en)//寻找st-->en的路径
{
    memset(pre,-1,sizeof(pre));
    while(!q.empty())q.pop();
    pre[st]=st,flow[st]=INT_MAX;
    q.push(st);
    while(!q.empty()){
        int top=q.front();
        q.pop();
        int now=head[top];
        while(now!=-1){
            int t=edge[now].v;
            if(pre[t]==-1 && edge[now].w>0){//该点没有被访问过,且权值不为0
                flow[t]=min(flow[top],edge[now].w);
                pre[t]=top;
                rec[t]=now;
                q.push(t);
            }
            now=edge[now].next;
        }
        if(pre[en]!=-1)
            return flow[en];
    }
    return -1;
}
LL EK(int st,int en)
{
    LL ans=0;
    LL add;
    while((add=bfs(st,en))!=-1){//走遍所有st-->en的路径
        ans+=add;
        int k=en;
       // printf("%d\n",add);
        while(k!=pre[k]){
            edge[rec[k]].w-=add;//权值减去最小值
            edge[rec[k]^1].w+=add;//反向边加上最小值
         //   printf("%d\n",k);
            k=pre[k];
        }
    }
    return ans;
}
int main()
{
    int x,y;
    LL c;
    while(scanf("%d%d",&m,&n)==2){
        init();
        for(int i=0;i<m;i++){
            scanf("%d%d%lld",&x,&y,&c);
            add(x,y,c);
        }
        printf("%lld\n",EK(1,n));
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值