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