Capacity Facility Location Problem
CFLP
Capacity Facility Location Problem,即有容量限制的设施选址问题,更准确地说,这次解决的问题为 SSCFLP(Single Source Capacity Facility Location Problem),其对资源的分配更为严格:每个顾客只能由一个设施来服务。下面我们来更准确地描述这个问题:
- 给定 m 个工厂,n 个用户
- 每个工厂有容量 ci 、建设费用 fi ( 1 <= i <= m )
- 每个用户有需求 di (1 <= i <= n)
- 对于每个用户 i ,不同的设施 j 的服务费用不同,表示为 costij
- 每个用户只能由一个设施服务,即 Single Source
求建设设施和服务每一个用户的费用总和的最小值。
方案
从问题描述来看,我们大概就能看出它并不是个善茬,它没有办法像解 LeetCode 上的题一样,用上一个简单算法,就能准确地求解,而事实上,它确实也是个 NP 难问题,所以穷搜绝对是行不通的,无论时间、空间服务度都是爆炸性的。所以不妨试试人工智能课上学到的近似求解方法:爬山法、模拟退火法、遗传算法以及禁忌搜索等。在这次实验中,我将依次使用贪心算法、局部搜索法(爬山法)、模拟退火法来逐渐提高解的质量。
贪心算法
对于每个用户 i ,不同的设施 j 的服务费用不同,利用这一点,我们可以想到一个简单的贪心策略:依次遍历每个用户 m ,找到其服务费用最少的设施 i:
- 如果设施 i 已开
- 如果容量不足,寻找服务费用仅次于它的下一个设施 j
- 如果容量充足,就选定 i
- 如果设施 i 未开,找到对该用户服务费用最少且容量充足的已开设施 j
- 如果 ( fj + costmi ) < costmj ,则选设施 i
- 否则,选设施 j
局部搜索法
我先用上述贪心算法产生一个初始解,这样可以减少算法的收敛时间,事实上贪心算法得到的解质量很差,这也就不用担心一开始就陷入局部最优啦,不过最重要的还是怎么去配合这个初解搜索领域,我使用了 4 种邻域搜索策略:
- 选定两个顾客,交换他们的服务设施,邻域空间为
n(n-1)/2
- 选定两个顾客,然后反转他们的服务设施,例如 [1, 3, 4, 2],我选中了顾客0和顾客3,则结果为 [2,4,3,1],邻域空间为
n(n-1)/2
- 选定两个已开设施,交换它们的客户,邻域空间为
O(m(m-1)/2)
- 选定一个顾客,将其转移到其它设施(已开和未开都行)
前三种策略是在已固定建设哪些设施的情况下,对顾客选择进行优化;而最后一种则是进一步在设施选址空间上进行扩张,而在实验过程中,证明在添加第 4 种策略后,解的质量会更上一层楼!
每次随机采用其中一种策略搜索邻域,如果找到更好的解,则接收;否则更换策略,直至再无策略可用。
模拟退火
与局部搜索算法略微不同的地方在于:局部搜索不接受比当前解更差的解。模拟退火有一个跳出局部最优的机制:若搜索的解劣于当前解,以一定的概率(与温度有关,温度越高概率越大)接受该劣解。
模拟退火的框架伪代码如下:
while temperature > lower_bound
for i=1:100
new_solution = search()
dcost = cost(new_solution) - cost(current_solution)
if dcost < 0
current_solution = new_solution
else
exp(-dcost / temperature) to receive new_solution
temperature *= COOLING_RATE
效果
贪心只是我拿来做局部搜索或模拟退火的一个踏板,所以我们主要看看后两者的效果,因为时间不太够,模拟退火没有细致地去调参,只是根据经验去随意设置了一下,同时在跑的时候,发现如果每次搜索邻域都穷搜某种搜索策略的解空间,耗时是相当恐怖的,所以我就限制了一下。下面是每种算法跑5次,目前最优
是这15次中最优的一次,模拟退火有时不比局部搜索做得好,有可能是还未收敛,但是可以看到,有些测例都跑了10来分钟了。
如果想看最优解,请直接拉到本文的最下面。
Result(avg.) | Time(s) | ||||||
---|---|---|---|---|---|---|---|
样例 | 目前最优 | 贪心 | 局部搜索 | 模拟退火 | 贪心 | 局部搜索 | 模拟退火 |
1 | 9929 | 16511 | 11579 | 10282 | 0 | 0 | 55 |
2 | 8928 | 12899 | 9803 | 9132 | 0 | 0 | 62 |
3 | 10420 | 18441 | 11604 | 10583 | 0 | 0 | 57 |
4 | 11811 | 22698 | 13116 | 12381 | 0 | 0 | 59 |
5 | 10209 | 17830 | 10561 | 10856 | 0 | 0 | 36 |
6 | 9025 | 12930 | 9679 | 9494 | 0 | 0 | 43 |
7 | 11204 | 20782 | 11726 | 11436 | 0 | 0 | 41 |
8 | 12334 | 23191 | 12833 | 13356 | 0 | 0 | 27 |
9 | 9543 | 13788 | 9849 | 9708 | 0 | 0 | 66 |
10 | 8778 | 11172 | 9102 | 8909 | 0 | 0 | 72 |
11 | 10221 | 20501 | 10468 | 10308 | 0 | 0 | 70 |
12 | 11397 | 21717 | 13049 | 11665 | 0 | 0 | 65 |
13 | 9271 | 17143 | 10588 | 9890 | 0 | 0 | 71 |
14 | 8113 | 12419 | 9001 | 8659 | 0 | 0 | 78 |
15 | 9955 | 16778 | 11502 | 10543 | 0 | 0 | 78 |
16 | 11805 | 23752 | 12232 | 12352 | 0 | 0 | 75 |
17 | 9297 | 18344 | 9993 | 9698 | 0 | 0 | 78 |
18 | 8482 | 12005 | 8808 | 8805 | 0 | 0 | 73 |
19 | 9804 | 18851 | 11202 | 10555 | 0 | 0 | 78 |
20 | 11890 | 22479 | 12402 | 12540 | 0 | 0 | 59 |
21 | 8826 | 16099 | 10114 | 9064 | 0 | 0 | 87 |
22 | 8375 | 11524 | 8859 | 8608 | 0 | 0 | 77 |
23 | 9956 | 17018 | 10803 | 10206 | 0 | 0 | 77 |
24 | 11015 | 22259 | 11794 | 11352 | 0 | 0 | 88 |
25 | 11630 | 18366 | 12073 | 13346 | 0 | 3 | 402 |
26 | 10575 | 17971 | 11573 | 12029 | 0 | 3 | 398 |
27 | 12675 | 18773 | 12795 | 13816 | 0 | 3 | 369 |
28 | 14642 | 25728 | 16824 | 16232 | 0 | 3 | 332 |
29 | 12630 | 21995 | 12932 | 13820 | 0 | 4 | 378 |
30 | 12109 | 17967 | 12658 | 12762 | 0 | 4 | 356 |
31 | 13628 | 27093 | 13765 | 15131 | 0 | 4 | 435 |
32 | 16054 | 29694 | 16129 | 20256 | 0 | 4 | 192 |
33 | 11620 | 17118 | 11647 | 14072 | 0 | 3 | 296 |
34 | 10928 | 17622 | 12332 | 11658 | 0 | 3 | 406 |
35 | 12200 | 17141 | 12286 | 15068 | 0 | 4 | 317 |
36 | 14878 | 22775 | 16029 | 16852 | 0 | 4 | 290 |
37 | 11120 | 15844 | 11120 | 13157 | 0 | 3 | 348 |
38 | 11297 | 15195 |