网络流专题
Part1 一些代码
(一)初始处理
1.最大流加边
struct Edge{int to,nxt,w;}e[SZ]; // w:流量
int Ecnt=2,Ehead[SZ];
il void Eadd(int u,int v)
{
e[Ecnt]=(Edge){v,Ehead[u],1};
Ehead[u]=Ecnt++;
e[Ecnt]=(Edge){u,Ehead[v],0};
Ehead[v]=Ecnt++;
}
2.费用流加边
struct Edge{int to,nxt,w,c;}e[SZ]; //w:流量,c:费用
int Ehead[SZ],pv[SZ],pe[SZ],Ecnt=2;
il void Eadd(int u,int v,int w,int cost)
{
e[Ecnt]=(Edge){v,Ehead[u],w,cost};
Ehead[u]=Ecnt++;
e[Ecnt]=(Edge){u,Ehead[v],0,-cost};
Ehead[v]=Ecnt++;
}
// pv[i] : spfa时使得i点dis值松弛的节点
//(最短路的上一节点)
//pe[i] : i与pv[i]连接的边
3.注意事项
对于原点和汇点 s = 0,t=n+2
Ecnt(边的起始编号)=2(一定不能是1)
(二)板子
1.最大流
int lev[SZ];
il bool bfs()
{
rg u,v;queue <int> Q;
memset(lev,-1,sizeof(lev));
lev[s]=1,Q.push(s);
while(!Q.empty())
{
u=Q.front(),Q.pop();
for(rg i=Ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(e[i].w>0&&lev[v]<0)
{
lev[v]=lev[u]+1;
Q.push(v);
}
}
}
if(lev[t]>0) return 1;
return 0;
}
int cur[SZ],Ans;
int dfs(int u,int f)
{
if(u==t||f==0) return f;
for(int &i=cur[u];i;i=e[i].nxt)
{
rg di=0,v=e[i].to;
if((lev[v]==lev[u]+1)&&(e[i].w>0))
if(di=dfs(v,min(f,e[i].w)))
{
e[i].w-=di,e[i^1].w+=di;
return di;
}
}
return 0;
}
il void maxflow()
{
rg di=0;
while(bfs())
{
for(rg i=s;i<=t;++i) cur[i]=Ehead[i];
while((di=dfs(s,INF))&&(Ans+=di));
}
printf("%d",Ans);
}
2.费用流
ll dis[SZ];
int vis[SZ];
queue <int> Q;
bool spfa()
{
memset(dis,63,sizeof(dis));
dis[s]=0; Q.push(s);
while(!Q.empty())
{
rg u=Q.front();
Q.pop();
for(rg i=Ehead[u];i;i=e[i].nxt)
{
rg v=e[i].to;
if((e[i].w)&&(dis[v]>dis[u]+e[i].c))
{
dis[v]=dis[u]+e[i].c;
pe[v]=i;
pv[v]=u;
if(!vis[v])
{
vis[v]=1;
Q.push(v);
}
}
}
vis[u]=0;
}
return dis[t]<dis[0];
}
il void costflow()
{
ll Ans=0;
while(spfa())
{
rg di=INF;
for(rg i=t;i!=s;i=pv[i])
di=min(di,e[pe[i]].w);
for(rg i=t;i!=s;i=pv[i])
{
e[pe[i]].w-=di;
e[pe[i]^1].w+=di;
Ans+=1ll*di*e[pe[i]].c;
}
}
printf("%lld",Ans);
}