const int null = -1; const int VMAX = 60000; const int EMAX = 1000000; struct Edge { int adj,next,re; //指向的点,下一边的下标,逆边的下标 int r; //余留网边的容量 }h[EMAX+10]; //用下标模拟指针构邻接表 int n,m,s,t; int p[VMAX+10],c; //各点的头指针,目前h数组开到的位置 int Q[VMAX+10],mark[VMAX+10]; int pre[VMAX+10]; //pre[i]记录广搜中指向i的边,即h[pre[i]].adj==i //插边,k,l为端点,cap为边容量 void insert(int k,int l,int cap) { 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; h[c].r=0; h[c].next=p[l]; p[l]=c; h[c].re=c-1; //与上面对应 } int EK() { int ans=0; int head,tail; while (1) { memset(mark,0,sizeof(mark)); mark[s]=1; head=tail=0; Q[tail++]=s; while (head<tail) { int k=Q[head++]; for (int i=p[k];i!=null && c;i=h[i].next) { int j=h[i].adj; if (!mark[j] && h[i].r) { pre[j]=i; mark[j]=1; if (j==t) break; Q[tail++]=j; } } if (mark[t]) break; } if (!mark[t]) break; int ca=inf,p,i=t; while (i!=s) { p=pre[i]; ca=min(ca,h[p].r); i=h[h[p].re].adj; } ans+=ca; i=t; while (i!=s) { p=pre[i]; h[p].r-=ca; h[h[p].re].r+=ca; i=h[h[p].re].adj; } } return ans; } void init() { c=-1; memset(p,-1,sizeof(p)); }