我的模板 最大流(Dinic & Isap)+最小費用最大流(SPFAFlow)==有更改

來源:互聯網
上載者:User

今天刻意用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;        }    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;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.