[算法设计与分析] CLFP 有容量限制的设施选址问题

Capacitated Facility Location Problems


代码都位于我的Github上,请点击这里查看

https://github.com/Gongzq5/Capacitated-Facility-Location-Problems


问题背景

Capacitated Facility Location Problem

  • Suppose there are n facilities and m customers. We wish to choose:
    • which of the n facilities to open
    • the assignment of customers to facilities
  • The objective is to minimize the sum of the opening cost and the assignment cost.
  • The total demand assigned to a facility must not exceed its capacity.

Problem Instance

1545555046846

问题参考

这个网站:http://www.di.unipi.it/optimize/Data/MEX.html

包含了问题的已知最优解

问题求解

解法1:模拟退火 SA

代码:

该解法代码文件位于 src/SA.cpp 中。

简介

就是普通的模拟退火,进行了如下的一些改进,并且参数经过了多次试验性的调整;

  • 邻域搜索策略:

采用5种邻域搜索策略

  1. 随机将一个客户移动到另一个仓库
  2. 随机改变一个仓库的状态
    • 若该仓库是打开的,那么尝试将该仓库的所有用户分配给其他仓库,然后关闭它;如果无法将所有用户都分配走,那么不恢复已被挪走的用户,也不改变该仓库的状态;
    • 若该仓库是关闭的,那么将该仓库打开,并且给这个仓库随机分配一个客户;
  3. 随机选择2个客户交换仓库
  4. 随机选择3个客户轮换仓库
  5. 随机选择4个客户轮换仓库

以上的策略在执行后都会验证,如果被挪走客户的仓库此时没有任何一个其他客户使用,那么将其关闭。

  • 额外的改进:
  1. 降温开始时记录一个阈值,在多次迭代不发生改变时,将温度升高至该阈值,然后阈值减半;

  2. 根据问题规模确定搜索次数(内循环次数),可以有效地处理问题规模增长后效果变差的情况。

基本参数设置
参数设置备注
初温 20 20 20初始温度
降温速率 0.99 0.99 0.99每轮循环后 T k + 1 = 0.99 T k T_{k+1} = 0.99 T_{k} Tk+1=0.99Tk
概率接受函数 r a n d o m ( ) &lt; e Δ H / ( T ∗ 5 ) random() &lt; e^{\Delta H/(T*5)} random()<eΔH/(T5)随机数 r r r小于该值时接受差解
内循环次数 p r o b l e m S i z e ⋅ 1.000 1 n problemSize \cdot 1.0001^n problemSize1.0001n初值根据问题规模确定,每次增加到 1.0001 1.0001 1.0001

解法2:贪心+局部搜索 Greedy + Local search

代码

该解法代码文件位于 src/GreedyLocalSearch.cpp 中。

简介

首先写了贪心的算法,贪心的算法在 src/GreedyLocalSearch.cpp 文件中有一个单独的函数可供查看;

然后写了局部搜索的算法;

单独贪心和局部搜索的结果都不是很好,想到可以将两者结合起来进行计算。首先先使用贪心法求一个初始解,然后使用局部搜索在此初始解附近迭代,试图找到最优解;

局部搜索使用的邻域搜索策略和模拟退火是相同的。

额外的改进:

  1. 为了避免问题的规模增加后代码运行次数不足的情况,我增加了根据问题规模决定循环次数的代码;

    int problemSize = instance.customerNum * instance.facilityNum;
    for (int _i; _i < problemSize * 2000; _i++) {...}
    
  2. 为了避免陷入局部最优,我增加了接受差解的代码,以期跳出局部最优;

    • 首先将接受差解的概率设置为0;
    • 在限定的循环次数内,如果有一定次数没有发现更优的解,会线性的增加接受差解的概率;
    • 由于参数的设定机制,接受差解的概率最多不会超过0.2,在实践中,通常不会超过0.01。但是取得的效果是显著的,在陷入局部最优(可能是全局最优)后会以较大的概率跳出该解,整个解检索的过程大致呈锯齿状分布;
    接受差解概率 badAcception = 0 
    FOR i FROM 0 TO (problemSize * 2000)
        {生成新解}
        IF {新解效果好} THEN
            {接收新解}
            badAcception = 0
        ELSE 
            {以概率badAcception接受差解}
            IF {不改变的次数大于 problemSize} THEN
                badAcception += 0.0001;
            END IF
        END IF
    END FOR
    
基本参数设置
参数设置备注
问题规模customerNum * facilityNum问题规模为客户数量乘以工厂的数量,用来衡量该问题的计算规模
差解接受概率0初值为0,不接受差解;每n次不产生新解则将其递增0.0001

附贪心算法的策略:

每次从客户的角度出发,贪心离他最近的工厂;

其判断到每个工厂的代价,计算为

IF facility[j] is open THEN
	cost = assignment cost
ELSE
	cost = assignment cost + opening cost
END IF

每次判断一个用户,如果该用户得到的最小代价是一个未打开的工厂的,那么就把这个工厂打开;如果是一个已打开的工厂,那么就只需要把用户指向这个工厂就好了。

实验结果

考虑到随机算法效果的随机性,为了充分考量算法的效果,我对每个测例进行了三次运行,结果放在结果文件夹的allSolutions文件夹中(命名为p1(1), p1(2)…),并挑出了其中最好的解放在optimizeSolutions文件夹中。

结果表格请查看 result.md 文件;

我还额外提供了一个结果矩阵的汇总的,命名为 summary

链接如下:

模拟退火贪心+局部搜索
所有实验解模拟退火三次实验的所有结果局部搜索三次实验的所有结果
所有最优解模拟退火每个测例的最优解局部搜索每个测例的最优解
结果汇总模拟退火每个测例具体结果的汇总局部搜索每个测例具体结果的汇总
结果表格模拟退火实验结果的表格局部搜索实验结果的表格

以下附结果表格

模拟退火结果如下

ResultTimes(s)
p188488
p279148
p393148
p4107956
p588388
p677777
p794887
p8110887
p985935
p1076277
p1189387
p12102528
p13829418
p14713717
p15886217
p161052420
p17829417
p18715216
p19890716
p201051417
p21817117
p22717816
p23877414
p241046319
p2511639106
p261077699
p2712336101
p2813736105
p2912548102
p3011337139
p3113378189
p3215376182
p3311632101
p3410635103
p3512235100
p361383599
p371132699
p381059498
p3911951107
p4013059125
p41673711
p42575532
p43530232
p44710714
p45658025
p46598036
p47707713
p48623925
p49560938
p50884813
p51741436
p52924615
p53853138
p54883823
p55765434
p5621748140
p5726379155
p5838059160
p5927694143
p6021241137
p6125596139
p6233662143
p6325397142
p6421400164
p6525794137
p6632688145
p6725231142
p6822086137
p6926100143
p7033316147
p7125679144

局部搜索结果如下

ResultTimes(s)
p188486s
p279145s
p393146s
p4108597s
p588386s
p677775s
p794886s
p8110886s
p984627s
p1076175s
p1189326s
p12101387s
p13825213s
p14718212s
p15886214s
p161061217s
p17822713s
p18718812s
p19888712s
p201051313s
p21806813s
p22715413s
p23880613s
p241032714s
p251163977s
p261078178s
p271234077s
p281373679s
p2912450153s
p3011391155s
p3113367217s
p3215387245s
p331170676s
p341063573s
p351223575s
p361383575s
p3711258116s
p381055148s
p391182469s
p401302472s
p4166407s
p42575014s
p43536920s
p4474627s
p45639613s
p46608320s
p4768369s
p48591014s
p49558419s
p5088618s
p51747117s
p5292537s
p53858918s
p54883419s
p55766321s
p562238467s
p572732168s
p583865169s
p592801569s
p602312267s
p612599566s
p623481667s
p632527968s
p642363766s
p6525958134s
p663312468s
p672748768s
p682231768s
p692525868s
p703310268s
p712643371s
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值