zkw费用流 java_zkw费用流 学习笔记

分析

记\(D_i\)为从\(S\)出发到\(i\)的最短路

最短路算法保证, 算法结束时

对于任意存在弧\((i,j)\)满足\(D_i + c_{ij}\ge D_j\) ①

且对于每个 \(j\) 至少存在一个 \(i\) 使得等号成立 ②

算法结束后, 恰在最短路上的边满足 \(D_j = D_i + c_{ij}\)

在最小费用流的计算中,我们每次沿 \(D_j = D_i + c_{ij}\)的路径增广

增广会让流量减小,会让部分的弧变得没有流量(即暂时不存在了)

是不会破坏①,但可能会破坏②的

这可能使我们找不到每条边都满足 $ D_j = D_i + c_{ij}$ 新的增广路

普通费用流的方法是:每次增广再使用 SPFA等方法重新计算\(D\)

这无疑是一种浪费

做法

\(D_i + c_{ij}\ge D_j~\Leftrightarrow~D_i-D_j+c_{ij}\ge 0~~\)①

\(D_i + c_{ij}= D_j~\Leftrightarrow~D_i-D_j+c_{ij}= 0~~\)②

对于一个顶标\(D\),我们可以不断的dfs找\(D_i-D_j+c_{ij}=0\)的增广路经

假设我们当前dfs失败

即使失败还是有一些点能满足\(D_i-D_j+c_{ij}=0\)的

这些点被我们当前dfs到了

我们记这些点的点集为\(V\)

找到\(\Delta= \min\left\{D_i-D_j+c_{ij} \right\} ~|~~ i \in V, j \notin V, flow_{~ij} > 0\)

然后我们对\(~~\forall i\in V ,~~D_i^{\pi}=D_i-\Delta\)

条件①②均没有被破坏

证明:

弧\((i,j)\)可以分成四类,再根据当前dfs失败的条件,有:

\[\begin{aligned}

i\in V,j\notin V &原来D_i-D_j+c_{ij} \ge \Delta> 0&新图 D_i^{\pi}-D_j+c_{ij}\ge 0\\

i\in V,j\in V &原来D_i-D_j+c_{ij} =0&新图 D_i^{\pi}-D_j^{\pi}+c_{ij}= 0\\

i\notin V,j\notin V &原来D_i-D_j+c_{ij}\ge 0&新图 D_i-D_j+c_{ij}\ge 0\\

i\notin V,j\in V &原来D_i-D_j+c_{ij} \ge 0&新图 D_i-D_j^{\pi}+c_{ij}\ge \Delta\\

\end{aligned}

\]

可以发现第一类弧中一定有至少一条满足

\(原来D_i-D_j+c_{ij}=\Delta~~~~~~~新图 D_i^{\pi}-D_j+c_{ij}=0\)的

即至少有一条新的边进入了 \(D_j = D_i + c_{ij}\) 的子图

可以发现一条增广路的流量为 -D[S]

实现

struct ZKW{

int flow,cost;

int D[M],V[M];

int aug(int x,int fl){

V[x]=1;

if(x==T) return cost+=-D[S]*fl, flow+=fl, fl;

int p,y,tp;

for(p=e(x);p;p=e[p].nxt)

if(e[p].f && !V[y=e[p].y] && D[x]+e[p].d-D[y]==0)

if(tp=aug(y,min(fl,e[p].f))) return e[p].f-=tp, e[p^1].f+=tp, tp;

return 0;

}

bool mdf(){

if(V[T]==1) return 1;

int i,x,y,z=INF;

for(i=2;i<=e.te;i++)

if(e[i].f&&V[x=e[i^1].y]&&!V[y=e[i].y]) z=min(z,D[x]+e[i].d-D[y]);

if(z==INF) return 0;

for(i=0;i<=T;i++) if(V[i]) D[i]-=z;

return 1;

}

void solve(int ned){

flow=0, cost=0;

memset(D,0,sizeof D);

do memset(V,0,sizeof V),aug(S,INF); while(mdf());

if(flow==ned) printf("%d\n",cost);

else puts("impossible");

}

}zkw;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值