最大流模板

自己写的模板,稍微挫了点儿但是容易理解... 用pku 1459 测试的模板,如发现错误请留言指出微笑

由于着急做题,只看了3种算法,Ford-Fulkerson,Edmonds-Karp(VE^2),Shortest Augment Path(SAP) (V^2 E),实现了后两种,什么dinic,预留推进之类的考完试再补吧,到时顺便复习一下。

看了别人博客,发现常用的算法分为增广路算法和预留推进算法两大类,Fulkerson,EK,SAP,dicnic都属于增广路算法,这两大类算法在算法导论里都有介绍,感觉对于我这种零基础的人《算法导论》的介绍比神牛总结的论文的效果要好...

Fulkerson是随便找一条增广路径进行增光,EK进行了优化用广搜找一条包含弧最少的增广路径(或者是权值最小的增广路径),SAP也是找最短增光路径,但是它将每个定点按距离汇点(或源点)的距离进行分类,多了一个d[i],代表顶点i所处的层数(个人理解),这个层数可以理解成广搜图的层数,那么从源点到汇点的一条最短增广路每层必须包含一个点且只能包含一个点,sap有个gap优化(间隙优化)就是基于d[i]的,我个人习惯叫gap优化为断层优化,我觉得”断层“更形象,如果某一层一个点都没有,自然就不可能找到增光路径了,sap还有一个当前弧优化,我不是很了解,不知道自己写的当前弧优化对不对...另外sap算法的时间分析我也不是很清楚,等找到论文看看论文里怎么说的吧...

Edmonds-Karp  pku 1459 469ms

//网络流Edmonds-Karp算法 
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define maxv 105
#define INF 0xfffffff
int n,result;
int f[maxv][maxv];//保存流 
int cf[maxv][maxv];//保存残余网络
queue<int> q;
int last[maxv];
int cfp[maxv];
bool inq[maxv];//是否进过queue 
bool bfs(int s,int t)
{
    int i,fm,to,ans;
    while(!q.empty())
        q.pop();
    memset(inq,0,sizeof(inq));
    memset(last,0,sizeof(last));
    inq[s]=1,q.push(s),cfp[s]=INF;
    while(!q.empty())
    {
        fm=q.front();
        q.pop();
        for(i=1;i<=n;++i)
        {
            to=i;
            if(cf[fm][to]&&!inq[to])
            {
                last[to]=fm;
                inq[to]=1;
                q.push(to);
                cfp[to]=min(cfp[fm],cf[fm][to]);
            }
        }
        if(inq[t])
            break;
    }
    if(inq[t])
    {
        ans=cfp[t],to=t,fm=last[to];
        result+=ans;
        while(fm!=0)
        {
            cf[fm][to]-=ans;
            cf[to][fm]+=ans;
            f[fm][to]+=ans;
            f[to][fm]=-f[fm][to];
            to=fm;
            fm=last[to];
        }
        return 1;
    }
    else
        return 0;
}
void Edmons_Karp(int s,int t)
{
    memset(f,0,sizeof(f));
    result=0;
    while(bfs(s,t));
    return ;
}
int main()
{
    int m,i,j,fm,to,cost,s,t;
    while(cin>>n>>m)
    {
        memset(cf,0,sizeof(cf));
        for(i=0;i<m;++i)
        {
            cin>>fm>>to>>cost;
            cf[fm][to]=cost;
        }
        cin>>s>>t;
        Edmons_Karp(s,t);
        cout<<result<<endl;
    }
    return 0;
}
        

 

SAP+gap+cur  79ms

//shortest augment path
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxv 105
#define INF 0xfffffff
int n,pn;
int G[maxv][maxv];
int d[maxv];
int cnt[maxv];   //gap断层优化
int cur[maxv];   //cur当前弧优化 
int p[maxv];
int exist(int u)
{
    int i;
    for(i=cur[u];i<=n;++i)
    {
        if(G[u][i]!=0&&d[u]==d[i]+1)
        {
            cur[u]=i;
            return i;
        }
    }
    return -1;    
}
void aug(int &f)
{
    int af=INF,i;
    for(i=0;i<pn-1;++i)
        af=min(af,G[p[i]][p[i+1]]);
    for(i=0;i<pn-1;++i)
    {
        G[p[i]][p[i+1]]-=af;
        G[p[i+1]][p[i]]+=af;
    }
    pn=0;
    f+=af;
    return ;
}
int renew(int u)
{
    cur[u]=1;
    int i,md=INF;
    bool flag=false;
    for(i=1;i<=n;++i)
    {
        if(G[u][i]!=0)
            md=min(md,d[i]),flag=true;
    }
    if(flag)
    {
        cnt[d[u]]--;
        if(cnt[d[u]]==0)
            return -1;
        cnt[md+1]++;
        d[u]=md+1;
        return 1;
    }
    else
        return 0;
}      
int SAP(int s,int t)
{
    pn=0;
    int f=0,i,j,flag;
    memset(d,0,sizeof(d));
    memset(cnt,0,sizeof(cnt));
    cnt[0]=n;
    for(i=1;i<=n;++i)
        cur[i]=1;
    i=s;
    while(d[s]<n)
    {
        if((j=exist(i))!=-1)
        {
            p[pn++]=i;
            i=j;
            if(i==t)
            {
                p[pn++]=t;
                aug(f);
                i=s;
            }
        }
        else
        {
            flag=renew(i);
            if(flag==-1)
                return f;
            else if(flag==0)
                d[i]=n;
            if(i!=s)
                i=p[--pn];            
        }
    }
    return f;
}
int main()
{
    int m,i,j,fm,to,cost,s,t;
    while(cin>>n>>m)
    {
        memset(G,0,sizeof(G));
        for(i=0;i<m;++i)
        {
            cin>>fm>>to>>cost;
            G[fm][to]=cost;
        }
        cin>>s>>t;
        cout<<SAP(s,t)<<endl;
    }
    return 0;
}    
     

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值