dinic(邻接表)模板

<textarea cols="81" rows="15" name="code" class="cpp">//用它做过一些题(hdu3046,poj3469等),正确性和效率都有待改进 //主要难题:如何在用邻接表表示余留网时迅速找到一条边的逆边? const int null = -1; const int VMAX = 40000; const int EMAX = 160000; struct Edge { int adj,next,re; //指向的点,下一边的下标,逆边的下标 int r; //余留网边的容量 }h[EMAX+10]; //用下标模拟指针构邻接表 int p[VMAX+10],c; //各点的头指针,目前h数组开到的位置 int Q[VMAX+10],level[VMAX+10]; //插边,k,l为端点,cap为边容量,d为是否双向 void insert(int k,int l,int cap,bool d) { h[++c].adj=l; h[c].r=cap; h[c].next=p[k]; p[k]=c; h[c].re=c+1; //****解决逆边问题的技巧,多存一个逆边在h中的位置**** //逆边 h[++c].adj=k; int a=d ? cap : 0; h[c].r=a; h[c].next=p[l]; p[l]=c; h[c].re=c-1; //与上面对应 } //广搜求层次图 bool bfs() { memset(level,-1,sizeof(level)); int head=0,tail=0; Q[tail++]=s; level[s]=0; while (head&lt;tail) { int v=Q[head++]; for (int i=p[v];i!=null;i=h[i].next) { int j=h[i].adj; if (level[j]==-1 &amp;&amp; h[i].r ) { level[j]=level[v]+1; Q[tail++]=j; } } } return (level[t]!=-1); } //深搜扩充流 int dfs(int v,int c) { if (v==t) return c; //遇汇点结束 int sum=c; for (int i=p[v];i!=null &amp;&amp; c;i=h[i].next) { int j=h[i].adj; if (h[i].r &amp;&amp; level[j]==level[v]+1) { int a=dfs(j,min(c,h[i].r)); //递归确定本次要扩充的流大小 h[i].r-=a; //增流 h[h[i].re].r+=a; c-=a; } } return sum-c; //返回从v点扩充的流大小 } //dinic算法主体,不断求层次图并增流,直至汇点不可达 int dinic() { int ans=0; while (bfs()) ans+=dfs(s,inf); return ans; } //初始化 void init() { c=-1; memset(p,null,sizeof(p)); //...... } </textarea>

你可能感兴趣的:(dinic(邻接表)模板)