zoukankan      html  css  js  c++  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= minleft{D_i-D_j+c_{ij} ight} ~|~~ i in V, j otin V, flow_{~ij} > 0)
    然后我们对(~~forall iin V ,~~D_i^{pi}=D_i-Delta)

    条件①②均没有被破坏
    证明:
    ((i,j))可以分成四类,再根据当前dfs失败的条件,有:

    [egin{aligned} iin V,j otin V &原来D_i-D_j+c_{ij} ge Delta> 0&新图 D_i^{pi}-D_j+c_{ij}ge 0\ iin V,jin V &原来D_i-D_j+c_{ij} =0&新图 D_i^{pi}-D_j^{pi}+c_{ij}= 0\ i otin V,j otin V &原来D_i-D_j+c_{ij}ge 0&新图 D_i-D_j+c_{ij}ge 0\ i otin V,jin 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
    ",cost);
    		else puts("impossible");
    	}
    }zkw;
    
  • 相关阅读:
    .net开发微信公众号(2)-验证服务器地址
    [广度遍历和深度遍历]聊聊算法和设计模式
    DDD领域驱动设计之聚合、实体、值对象
    DDD领域驱动设计之运用层代码
    DDD领域驱动设计之领域服务
    DDD领域驱动设计之领域基础设施层
    DDD领域驱动设计实践篇之如何提取模型
    Docker最全教程——从理论到实战(七)
    Docker最全教程——从理论到实战(六)
    Docker最全教程——从理论到实战(五)
  • 原文地址:https://www.cnblogs.com/acha/p/6735037.html
Copyright © 2011-2022 走看看