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<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 && 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 && c;i=h[i].next)
{
int j=h[i].adj;
if (h[i].r && 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));
//......
}