[置顶] 我的模板 最大流(Dinic & Isap)+最小费用最大流(SPFAFlow)==有更改

今天刻意用poj 3469 http://poj.org/problem?id=3469测了下模板,Isap并不像想象中那么快,难道是我写搓了尴尬,而且在网络流与线性规划中的最后一题,isap完败给Dinic了,我的Isap啊~~~不知道那些几百毫秒出解的是用什么算法。。。难道是。。。抓狂

   dinic总体上挺不错的,递归版的Isap基本上与Dinic没差别,而非递归版在某些情况反而不如递归版,于是以后一般用Dinic,是在不行用非递归的isap试试

所以比赛中就带1,3两个模板好了

费用流居然忘加了,今天把它加上了= =,在最后。。。

模板1(Dinic递归版 3438MS):

#include<cstdio>
using namespace std;
const int mm=1000000;
const int mn=22222;
const int oo=1000000000;
int node,src,dest,edge;
int reach[mm],flow[mm],next[mm];
int head[mn],work[mn],dis[mn],q[mn];
inline int min(int a,int b)
{
    return a<b?a:b;
}
inline void prepare(int _node,int _src,int _dest)
{
    node=_node,src=_src,dest=_dest;
    for(int i=0;i<node;++i)head[i]=-1;
    edge=0;
}
inline void addedge(int u,int v,int c1,int c2)
{
    reach[edge]=v,flow[edge]=c1,next[edge]=head[u],head[u]=edge++;
    reach[edge]=u,flow[edge]=c2,next[edge]=head[v],head[v]=edge++;
}
bool Dinic_bfs()
{
    int i,u,v,l,r=0;
    for(i=0;i<node;++i)dis[i]=-1;
    dis[q[r++]=src]=0;
    for(l=0;l<r;++l)
        for(i=head[u=q[l]];i>=0;i=next[i])
            if(flow[i]&&dis[v=reach[i]]<0)
            {
                dis[q[r++]=v]=dis[u]+1;
                if(v==dest)return 1;
            }
    return 0;
}
int Dinic_dfs(int u,int exp)
{
    if(u==dest)return exp;
    for(int &i=work[u],v,tmp;i>=0;i=next[i])
        if(flow[i]&&dis[v=reach[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)
        {
            flow[i]-=tmp;
            flow[i^1]+=tmp;
            return tmp;
        }dis[u]--;
    return 0;
}
int Dinic_flow()
{
    int i,ret=0,delta;
    while(Dinic_bfs())
    {
        for(i=0;i<node;++i)work[i]=head[i];
        while(delta=Dinic_dfs(src,oo))ret+=delta;
    }
    return ret;
}
int main()
{
    int i,j,n,m,a,b;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        prepare(n+2,0,n+1);
        for(i=1;i<=n;++i)
        {
            scanf("%d%d",&a,&b);
            addedge(src,i,a,0);
            addedge(i,dest,b,0);
        }
        while(m--)
        {
            scanf("%d%d%d",&i,&j,&a);
            addedge(i,j,a,a);
        }
        printf("%d\n",Dinic_flow());
    }
    return 0;
}

模板2:(Isap递归版 3094MS)

#include<cstdio>
using namespace std;
const int mm=2000000;
const int mn=22222;
const int oo=1000000000;
int node,src,dest,edge;
int reach[mm],flow[mm],next[mm];
int head[mn],gap[mn],h[mn];
inline int min(int a,int b)
{
    return a<b?a:b;
}
inline void prepare(int _node,int _src,int _dest)
{
    node=_node,src=_src,dest=_dest;
    for(int i=0;i<node;++i)head[i]=-1;
    edge=0;
}
inline void addedge(int u,int v,int c1,int c2)
{
    reach[edge]=v,flow[edge]=c1,next[edge]=head[u],head[u]=edge++;
    reach[edge]=u,flow[edge]=c2,next[edge]=head[v],head[v]=edge++;
}
int Isap_dfs(int u,int exp)
{
    if(u==dest)return exp;
    int i,v,minh=node,lv=exp,tmp;
	for(i=head[u];i>=0;i=next[i])
		if(flow[i])
		{
			if(h[v=reach[i]]+1==h[u])
			{
				tmp=Isap_dfs(v,min(lv,flow[i]));
				flow[i]-=tmp;
				flow[i^1]+=tmp;
				lv-=tmp;
				if(h[src]>=node)return exp-lv;
				if(lv==0)break;
			}
			minh=min(minh,h[v]);
		}
	if(lv==exp)
	{
		if(--gap[h[u]]==0)h[src]=node;
		++gap[h[u]=minh+1];
	}
	return exp-lv;
}
int Isap_flow()
{
    int i,ret=0;
	for(i=0;i<node;++i)gap[i]=h[i]=0;
	gap[0]=node;
	while(h[src]<node)ret+=Isap_dfs(src,oo);
	return ret;
}
int main()
{
    int i,j,n,m,a,b;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        prepare(n+2,0,n+1);
        for(i=1;i<=n;++i)
        {
            scanf("%d%d",&a,&b);
            addedge(src,i,a,0);
            addedge(i,dest,b,0);
        }
        while(m--)
        {
            scanf("%d%d%d",&i,&j,&a);
            addedge(i,j,a,a);
        }
        printf("%d\n",Isap_flow());
    }
    return 0;
}

模板3(Isap 非递归版 2610MS):

这个模板有bug, 出现在gap优化里,详细看红色注释

#include<cstdio>
using namespace std;
const int mm=2000000;
const int mn=22222;
const int oo=1000000000;
int node,src,dest,edge;
int ver[mm],flow[mm],next[mm];
int head[mn],work[mn],h[mn],q[mn],gap[mn],p[mn];
inline int min(int a,int b)
{
    return a<b?a:b;
}
inline void prepare(int _node,int _src,int _dest)
{
    node=_node,src=_src,dest=_dest;
    for(int i=0; i<node; ++i)head[i]=-1;
    edge=0;
}
inline void addedge(int u,int v,int c1,int c2)
{
    ver[edge]=v,flow[edge]=c1,next[edge]=head[u],head[u]=edge++;
    ver[edge]=u,flow[edge]=c2,next[edge]=head[v],head[v]=edge++;
}
void Isap_Pre()
{
    int i,u,v,l,r=0;
    for(i=0; i<node; ++i)h[i]=gap[i]=0;//高度初始为0,否则会访问-1的数组,汇点为1
    gap[h[q[r++]=dest]=1]=1;
    for(l=0; l<r; ++l)
        for(i=head[u=q[l]]; i>=0; i=next[i])
            if(flow[i^1]&&!h[v=ver[i]])
                ++gap[h[q[r++]=v]=h[u]+1];
}
int Isap_flow()
{
    int i,u,ret=0,tmp,minh;
    Isap_Pre();
    for(i=0; i<node; ++i)work[i]=head[i];
    u=src;
    while(h[src]<=node)//高度相应增加,改成>=
    {
        if(u==dest)
        {
            for(i=src,tmp=oo;i!=dest;i=ver[work[i]])
                tmp=min(tmp,flow[work[i]]);
            for(i=src;i!=dest;i=ver[work[i]])
                flow[work[i]]-=tmp,flow[work[i]^1]+= tmp;
            ret+=tmp,u=src;
        }
        int &e=work[u];
        for(;e>=0;e=next[e])
            if(flow[e]&&h[u]==h[ver[e]]+1)break;
        if(e>=0)p[u=ver[e]]=e^1;
        else
        {
            if(--gap[h[u]]==0)break;
            work[u]=head[u],minh=node;
            for(i=head[u];i>=0;i=next[i])
                if(flow[i])minh=min(minh,h[ver[i]]);
            ++gap[h[u]=minh+1];//应该是h[u]=max(h[u],minh)+1,否则gap[h[u]]==0时断层并不能结束,因为可能会降低h[u]导致断层恢复
            if(u!=src)u=ver[p[u]];
        }
    }
    return ret;
}
int main()
{
    int i,j,n,m,a,b;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        prepare(n+2,0,n+1);
        for(i=1;i<=n;++i)
        {
            scanf("%d%d",&a,&b);
            addedge(src,i,a,0);
            addedge(i,dest,b,0);
        }
        while(m--)
        {
            scanf("%d%d%d",&i,&j,&a);
            addedge(i,j,a,a);
        }
        printf("%d\n",Isap_flow());
    }
    return 0;
}


改正后的ISAP非递归版本,对应csu 1249,谢谢wyb的数据:

#include<cstdio>
#include<iostream>
using namespace std;
const int mm=20000;
const int mn=222;
const int oo=1000000000;
int node,src,dest,edge;
int ver[mm],flow[mm],next[mm];
int head[mn],work[mn],h[mn],q[mn],gap[mn],p[mn],cur[mn];
void prepare(int _node,int _src,int _dest)
{
    node=_node,src=_src,dest=_dest;
    for(int i=0; i<node; ++i)head[i]=-1;
    edge=0;
}
void addedge(int u,int v,int c)
{
    ver[edge]=v,flow[edge]=c,next[edge]=head[u],head[u]=edge++;
    ver[edge]=u,flow[edge]=0,next[edge]=head[v],head[v]=edge++;
}
void Isap_Pre()
{
    int i,u,v,l,r=0;
    for(i=0; i<node; ++i)h[i]=gap[i]=0;//高度初始为0,汇点为1
    h[q[r++]=dest]=1;
    for(l=0; l<r; ++l)
        for(i=head[u=q[l]]; i>=0; i=next[i])
            if(flow[i^1]&&!h[v=ver[i]])
                h[q[r++]=v]=h[u]+1;
    for(i=0; i<node; ++i)++gap[h[i]];//统计高度个数
}
int Isap_flow()
{
    int i,j,u,ret=0,tmp,minh,deep=0;
    Isap_Pre();
    for(i=0; i<node; ++i)work[i]=head[i];
    p[0]=u=src,cur[0]=oo;
    while(h[src]<=node)
    {
        if(u==dest)
        {
            tmp=cur[deep],deep=0,u=-1;
            for(i=src;i!=dest;i=ver[j])
            {
                flow[j=work[i]]-=tmp,flow[j^1]+= tmp;
                if(u<0)!flow[j]?u=i:cur[++deep]-=tmp;
            }
            ret+=tmp;
        }
        int &e=work[u];
        for(;e>=0;e=next[e])
            if(flow[e]&&h[u]==h[ver[e]]+1)break;
        if(e>=0)
        {
            p[++deep]=u=ver[e];//栈记录节点
            cur[deep]=min(cur[deep-1],flow[e]);//栈记录最大流量
            continue;
        }
        if(--gap[h[u]]==0)break;
        work[u]=head[u],minh=node;
        for(i=head[u];i>=0;i=next[i])
            if(flow[i])minh=min(minh,h[ver[i]]);
        ++gap[h[u]=max(h[u],minh)+1];//一定要比本身大否则gap优化会出错
        if(deep>0)u=p[--deep];
    }
    return ret;
}
int main()
{
    int i,j,n,m,a;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        prepare(n+1,1,n);
        while(m--)
        {
            scanf("%d%d%d",&i,&j,&a);
            addedge(i,j,a);
        }
        scanf("%d%d",&src,&dest);
        printf("%d\n",Isap_flow());
    }
    return 0;
}



最小费用最大流,当然最大费用直接把边去相反数即可转换为最小费用。。。

题目:http://acm.hit.edu.cn/hoj/problem/view?id=2715

模板:

#include<cstdio>
#include<iostream>
using namespace std;
const int mm=66666;
const int mn=5555;
const int oo=1e9;
int src,dest,node,edge;
int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};
int ver[mm],cost[mm],flow[mm],next[mm];
int head[mn],dis[mn],p[mn],q[mn];
int h[55][55];
bool vis[mn]={0};
void prepare(int _node,int _src,int _dest)
{
    node=_node,src=_src,dest=_dest;
    for(int i=0;i<node;++i)head[i]=-1;
    edge=0;
}
void addedge(int u,int v,int f,int c)
{
    ver[edge]=v,flow[edge]=f,cost[edge]=c,next[edge]=head[u],head[u]=edge++;
    ver[edge]=u,flow[edge]=0,cost[edge]=-c,next[edge]=head[v],head[v]=edge++;
}
bool Spfa()
{
    int i,u,v,l,r=0,tmp;
    for(i=0;i<node;++i)dis[i]=oo;
    dis[q[r++]=src]=0;
    p[src]=p[dest]=-1;
    for(l=0;l!=r;(++l==mn)?l=0:l)
        for(i=head[u=q[l]],vis[u]=0;i>=0;i=next[i])
            if(flow[i]&&dis[v=ver[i]]>(tmp=dis[u]+cost[i]))
            {
                dis[v]=tmp;
                p[v]=i^1;
                if(vis[v])continue;
                vis[q[r++]=v]=1;
                if(r==mn)r=0;
            }
    return p[dest]>-1;
}
int Spfaflow()
{
    int i,delta,ret=0;
    while(Spfa())
    {
        for(i=p[dest],delta=oo;i>=0;i=p[ver[i]])
            if(flow[i^1]<delta)delta=flow[i^1];
        for(i=p[dest];i>=0;i=p[ver[i]])
            flow[i]+=delta,flow[i^1]-=delta;
        ret-=delta*dis[dest];
    }
    return ret;
}
int main()
{
    int i,j,x,y,k,n,m,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        prepare(n*n*2+3,n*n*2+1,n*n*2+2);
        for(i=0;i<n;++i)
            for(j=1;j<=n;++j)
            {
                scanf("%d",&k);
                addedge(0,i*n+j,oo,0);
                addedge(i*n+j,n*n+i*n+j,1,-k);
                addedge(i*n+j,n*n+i*n+j,oo,0);
            }
        for(i=1;i<=n;++i)
            for(j=1;j<=n;++j)
                scanf("%d",&h[i][j]);
        for(i=1;i<=n;++i)
            for(j=1;j<=n;++j)
                for(k=0;k<4;++k)
                {
                    x=i+dx[k];
                    y=j+dy[k];
                    if(x<1||x>n||y<1||y>n||h[x][y]>=h[i][j])continue;
                    addedge(n*n+i*n-n+j,x*n-n+y,oo,0);
                }
        for(i=1;i<=n;++i)
            for(j=1;j<=n;++j)
                if(i==1||j==1||i==n||j==n)
                    addedge(n*n+n*i-n+j,dest,oo,0);
        addedge(src,0,m,0);
        printf("%d\n",Spfaflow());
    }
    return 0;
}


你可能感兴趣的:(c,算法,网络,OO)