• 最小费用流算法不完全指南-2017华为软件精英挑战赛


    1.前言

    整个比赛历时70多天,是一场持久战,期间看了不少资料,实现了一些算法,现总结如下。

    初赛的思路是启发式+费用流,启发式实现了遗传算法、模拟退火,费用流实现了连续最短路(spfa),zkw/primal-dual,网络单纯形(决赛写的),这些算法其实都不是自己手写的,是从网上的模板改造过来的。

    初赛规模用退火还可以,到了复赛,服务器分等级,规模变得更大了,费用流的次数完全不能满足退火的需求,于是放弃找全局最优,直接贪心找局部最优。

    决赛题目大变化,可怜我花了一周的时间整了个网络单纯形,后来才发现根本没有用上。决赛主要是想策略,对费用流的速度要求不是那么高。

    2.小费用最大流问题求解算法

    先说一下小费用最大流问题求解算法有哪些,从《网络优化》(谢金星 et al., 2009)一书中可以看到,求解该问题有如下这些方法:

    • 消圈算法
    • 最小费用路算法(连续最短路)
    • 原始-对偶算法
    • 瑕疵算法
    • 松弛算法
    • 网络单纯形算法

    还有一个zkw算法不在这本书中,其实zkw用于比赛,效率非常高。

    2.1最小费用路算法(连续最短路)

    这算法的实现来自于《算法竞赛入门经典(第2版)(算法艺术与信息学竞赛)》(刘汝佳,2014)一书,当时正好在看这本书,就直接用这里的算法了,包括图的存储结构也用的这本书里面的,应该叫做前向星。

    2.2 zkw/primal-dual

    问题规模变大后,前面的算法速度已经跟不上了,就得去找新的算法,一开始就听说松弛和网络单纯形很快,但是觉得它们实现起来很麻烦,想找一个简单一点的,就发现了zkw(从入门到精通: 最小费用流的“zkw算法”),连续最短路是一条路一条路的增广,而zkw是多路增广,快了不少。

    2.3网络单纯形算法

    进决赛后,题目还没有定下来的时候,我们觉得应该看看网络单纯形,要是规模继续变大,zkw可能也跟不上,搜了搜网络单纯形的开源库,找到3个,分别测试了一下,时间上,如果zkw要30ms,网络单纯形可以10ms,还是有一定的价值实现。网络单纯形的大概原理可以看《网络优化》(谢金星 et al., 2009)。

    不过要注意网络单纯形并不等同于线性规则里面的单纯形,可以看看《运筹学(第三版),清华大学出版社》。

    我搜到的网络单纯形的3个开源库分别是:

    NetworkX可能是因为python的原因,速度非常慢,看它的源码和LEMON很像。

    2.3.1 MCFClass project

    进去需要翻墙,下载下来后在说明文档中有“How to Use It”,可以参照进行使用,注意需要将图存为它规定的格式,这里提供2个测试例子。一个是800点的图,服务器位置使用最优解的位置。一个是第三批练习用例里面的case0,这个例子有1200个点,5267条边,480个消费点,服务器位置是跑退火得到的位置。设置一个超级源点,连接所有服务器,设置一个超级源点,连接所有消费点。两个case可以在这里下载,数据格式在文档中可以查看。

    所以,如果想要快速上手使用它,可按照如下步骤进行(以win, vs2013为例):

    1.下载源码,下载我提供的case

    2.新建一个vs工程,创建h文件和cpp文件,把下载下来的文件内容复制过去,或者直接替换(用c文件好像会出问题,不行就用cpp)

    3.编译(release)

    4.把下载的case放在release文件夹中,在当前文件夹中打开命令行,运行:

    ***.exe case**.txt

    就可以看到结果了,结果会显示时间和最小费用。

    2.3.2 LEMON

    LEMON里面的最小费用流算法由(Király and Kovács, 2012)完成,可以参考他们的文章:Király, Z. and Kovács, P., 2012. Efficient implementations of minimum-cost flow algorithms. Computer Science.文章对他们的网络单纯形算法进行了介绍。

    在windows下的安装方法,不出意外的话,按照里面提供的方法可以产生一个vs工程。LEMON同样需要使用它指定的数据格式,可以参照文档说明进行生成,这里提供一个我生成的case是1200点的图,服务器位置使用退火获得的(随意跑的?还是哪来的?忘了),设置一个超级源点,连接所有服务器,设置一个超级源点,连接所有消费点,case可以在这里下载。

    所以,如果想要快速上手使用它,可按照如下步骤进行(以win, vs2013为例):

    1.下载源码,在windows下安装(方法

    2.下载我提供的case(可以在这里下载),下载后放在...lemon-1.3.1uilddemo下。

    3.为了测试方便,我直接把lgf_demo.cc修改了,修改后的源码在这里,下载下来放到lgf_demo.cc中。

    3.把lgf_demo设为启动项,在release模式下运行,就可以看到结果了。

    注意:

    • LEMON实现了好几种搜索入弧的方式,默认的是BLOCK_SEARCH,说这个的效率高且稳定、实现起来比较简单,ALTERING_LIST可能效率高但不稳定,实现要复杂一些。
    • 存储边的时候采用了乱序存储,这样可以提高效率,我没有搞明白为什么,如果我不采样乱序存储速度确实会变慢。这里说的乱序就直接按照数据文件读取的时候边的顺序是1,2,3,4,5,6,7,8,9,10.那么存的时候就按一定的间隔存,比如间隔为2,那么存起来就是这样的:1,3,5,7,9,2,4,6,8,10.
    • 网络单纯形居然也有参数要调整,比如BLOCK_SEARCH的块大小,如果为1就退化成了FIRST_ELIGIBLE,如果太大或者直接是边数,那么就成了BEST_ELIGIBLE.

    2.3.3 NetworkX

    我感觉NetworkX里面的网络单纯形像是从LEMON里面提取出来后简化过的,测试发现花的时间很长,可能是因为python的缘故。

    同样,如果想要快速上手使用它,可按照如下步骤进行(以win, python3为例,我用的anaconda):

    1.按照文档说明进行安装

    2.它也需要一定的数据格式,这里提供一个可以用的case(下载),是第三批高级case0,1200个点。

    3.下载测试脚本

    4.运行就可以看到结果

    补充:

    netcan指出还有ξ松弛,拍卖算法里的,不用退流,但无解的情况特别慢,提供流量和需求流量不一样得到的解也不对。

    github:https://github.com/hubenjm/mincostflow

  • 相关阅读:
    poj 1523 SPF (无向图 的 割点)
    codeforces Walking in the Rain (dp 水题 线性 dp)
    GaleShapley算法
    hdu 1087 Super Jumping! Jumping! Jumping! (最大 上升子序列 线性 dp)
    poj 3694 Network (无向图的 割边 lca )
    codeforces To Add or Not to Add (排序 + 优化)
    hdu 3996 Gold Mine ( 最大权闭合图 )
    转:WINFORM多线程编程
    C#串口serialPort操作
    用C# 根据 JSC100 V5.0读写器通讯协议 编写读卡器API
  • 原文地址:https://www.cnblogs.com/shanchuan/p/8150284.html
Copyright © 2020-2023  润新知