最短增广路
求最大流的高效算法
回忆Dinic:
数组dis[i]记录源点到点i的最短距离。g[i][j]记录边(i,j)的容量
算法过程如下: 1.初始化,将dis数组全部置为-1,dis[源]赋值为0 2.通过BFS计算每个点的dis,若算出dis[汇]=-1,则算法结束。 3.从源点出发,用DFS找增广路。 对于点x,若存在边(x,y),点y若要加入增广路就必须满足条件: g[x][y]>0 并且 dis[x]+1=dis[y] 4.重复2,3,直到找不到增广路。
时间复杂度 O(v2e)!!!
SAP算法框架:
数组dis[i]记录点i到汇点的最短距离。g[i][j]记录边(i,j)的容量。
算法过程如下:
1.初始化,计算出每个点的dis
2.从源点出发,用DFS找增广路: 对于点x,若存在边(x,y),点y若要加入增广路就必须满足条件: g[x][y]>0 并且 dis[x]-1=dis[y] (边(x,y)称为允许边) 若对于点x,找不到满足上诉条件的y:dis[x]++
3.若走到汇点(找到增广路),修改增广路上每条边的容量,返回上一个点,继续搜索,......直到找不到增广路。
何时结束寻找增广路?出现短路时。
数组vd[i]记录到汇点距离为i的点出现的次数
若某时vd[i]变为0或者dis[源]>=n,表示出现断路。
代码:
const int inf=1000000000;
int g[201][201],vd[201],dis[201],m,n,x,y,z,flow,ans,i;
int dfs(int u,int flow)//搜索点u,从u的前一个点传过来的水流量大小为flow,也就是流入u的水量为flow
{ int v,temp,delta;
if(u==n)return flow;//若u为汇点,表示找到增广路,返回可增广的流量值
delta=0;//delta记录从u流出去的水量
for(v=1;v<=n;v++) //依次判断和u相连的点是否满足增广条件
if(g[u][v]>0 && dis[u]==dis[v]+1)
{
temp=dfs(v,min(flow-delta,g[u][v]));/搜索增广路,从u流向v的流量应该是flow和g[u][v]间的小者
g[u][v]-=temp;
g[v][u]+=temp;
delta+=temp;//找到增广路后并不退回到源点重新增广,而是把增广值存在temp里,继续从u增广
if(delta==flow||dis[1]>=n) return delta;//如果dis[1]>=n,说明源点无法到达汇点,结束搜索
}//delta=flow说明u把流进它的水完全传了出去,表示已无可增广的流量,结束对u的增广
vd[dis[u]]--;/若找不到增广路,把dis[u]+1,同时修改vd[]数组
if(vd[dis[u]]==0)dis[1]=n;
dis[u]=dis[u]+1;
vd[dis[u]]++;
return delta;
}
int main()
{ cin>>m>>n; for(i=1;i<=m;i++) { cin>>x>>y>>z; g[x][y]+=z ;}
while(dis[1]<n)
{
flow=dfs(1,inf);
ans+=flow;
}
cout<<ans<<endl; return 0;
}
中等稠密图
稀疏图
稠密图