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 tofacilities
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.
简而言之就是存在n个工厂,每个工厂有各自的容量上限和开启花费,现在有m个顾客,当一个工厂的剩余容量大于等于某个顾客的需求时,这个工厂才能为这个顾客服务,不同的工厂服务同一个顾客的花费也不同。每个顾客都需要被服务到,怎样安排能使工厂的开启花费和顾客服务花费总和最小。
对于某一个合法的样例来说肯定是存在最优解的,但并不是那么容易求的,老师也不作这方面的要求,只要求用2种不同的方法求好解,因此我选择了最常见的贪心算法和这学期新学的模拟退火(SA)算法,下面我将一一介绍2种方法的实现。
贪心算法
我用的是较为简单的贪心思路,因为有n个工厂,每个顾客自然有n个对应cost,按照某种标准给n个工厂排序,形成第一志愿工厂、第二志愿工厂…起初我是按照顾客在每个工厂的服务花费customer.cost[i]与工厂的开启花费facility[i].cost之和为标准排序,后来经过实验发现,用两个花费的和不如单按照服务花费customer.cost[i]为标准排序求得的结果好。我的猜想是工厂的开启花费往往比服务花费大得多,而且工厂只要开启了就不再需要额外的花费,如果给顾客的服务花费排序时算上工厂开启花费,会对排序结果有较大的影响,差解排在好解前面的概率大大增加。
经过排序后,每个顾客都有了各自的第一志愿工厂,再按照第一志愿工厂的服务花费对顾客进行排序,第一志愿工厂服务花费少的顾客优先分配。分配的原则是如果第一志愿工厂剩余容量足够,就把顾客分配到第一志愿工厂,否则把志愿往后按序推移。
这种贪心的思路总的来说很简单,就是通过两次排序决定顾客和各自志愿工厂优先处理顺序,然后根据排序结果分配。但问题也是显而易见的,就是没有考虑到顾客组合的影响,比如A、B两个顾客占用了工厂1,但其实A、C两个顾客占用工厂1能使花费更少,但却因为C的优先级在B后面,导致A、B分配到工厂1后没有剩余容量能容下C。因此这个贪心算法只能求得局部最优,往往求不到最优解,与最优解的差距和最优解的顾客组合复杂性有关。
| 测试样例 | 结果 | 时间 |
|---|---|---|
| p1 | 9472 | 0.000 |
| p2 | 8158 | 0.000 |
| p3 | 10158 | 0.000 |
| p4 | 12158 | 0.000 |
| p5 | 9661 | 0.000 |
| p6 | 8347 | 0.000 |
| p7 | 10347 | 0.000 |
| p8 | 12347 | 0.000 |
| p9 | 9040 | 0.000 |
| p10 | 7726 | 0.001 |
| p11 | 9726 | 0.000 |
| p12 | 11726 | 0.000 |
| p13 | 12032 | 0.000 |
| p14 | 12032 | 0.000 |
| p15 | 13180 | 0.000 |
| p16 | 17180 | 0.000 |
| p17 | 12032 | 0.000 |
| p18 | 9180 | 0.000 |
| p19 | 13180 | 0.000 |
| p20 | 17180 | 0.000 |
| p21 | 12032 | 0.000 |
| p22 | 9180 | 0.001 |
| p23 | 13180 | 0.000 |
| p24 | 17180 | 0.000 |
| p25 | 19189 | 0.001 |
| p26 | 16123 | 0.001 |
| p27 | 21523 | 0.001 |
| p28 | 26923 | 0.001 |
| p29 | 19145 | 0.001 |
| p30 | 16079 | 0.002 |
| p31 | 21479 | 0.001 |
| p32 | 26879 | 0.001 |
| p33 | 19055 | 0.001 |
| p34 | 15989 | 0.001 |
| p35 | 21389 | 0.001 |
| p36 | 26789 | 0.001 |
| p37 | 19055 | 0.001 |
| p38 | 15989 | 0.001 |
| p39 | 21389 | 0.001 |
| p40 | 26789 | 0.001 |
| p41 | 7218 | 0.000 |
| p42 | 9957 | 0.000 |
| p43 | 12448 | 0.001 |
| p44 | 7567 | 0.001 |
| p45 | 9848 | 0.000 |
| p46 | 12639 | 0.001 |
| p47 | 6777 | 0.001 |
| p48 | 9044 | 0.001 |
| p49 | 12420 | 0.000 |
| p50 | 10184 | 0.001 |
| p51 | 11388 | 0.000 |
| p52 | 11966 | 0.000 |
| p53 | 13167 | 0.000 |
| p54 | 10993 | 0.000 |
| p55 | 12013 | 0.000 |
| p56 | 23882 | 0.002 |
| p57 | 32882 | 0.001 |
| p58 | 53882 | 0.002 |
| p59 | 39121 | 0.001 |
| p60 | 23882 | 0.001 |
| p61 | 32882 | 0.001 |
| p62 | 53882 | 0.001 |
| p63 | 39121 | 0.001 |
| p64 | 23882 | 0.001 |
| p65 | 32882 | 0.001 |
| p66 | 53882 | 0.001 |
| p67 | 39671 | 0.002 |
| p68 | 23882 | 0.001 |
| p69 | 32882 | 0.002 |
| p70 | 53882 | 0.001 |
| p71 | 39121 | 0.001 |
#include <iostream>
#include <fstream>
#include <time.h>
using namespace std;
typedef struct {
int capacity; //工厂容量
int cost; //工厂开启的花费
int occupy; //当前已经使用的容量
}facility;
typedef struct {
int demand; //容量需求
int *cost; //对每个工厂的花费
int *costID; //记录每个花费对应的是哪个工厂
}customer;
void greedy(string file){
//读取文件
ifstream infile("./Instances/p" + file);
ofstream outfile("./Greedy_output", ios::app);
int facilityNum, customerNum;
float temp;
infile >> facilityNum >> customerNum;
facility *facilities = new facility[facilityNum];
customer *customers = new customer[customerNum];
for (int i = 0; i < facilityNum; i++){
infile >> facilities[i].capacity >> facilities[i]

本文探讨了Capacitated Facility Location Problem,通过贪心算法和模拟退火(SA)算法寻求解决方案。贪心算法通过两次排序分配顾客,但只能得到局部最优解;模拟退火算法允许接受差解,以跳出局部最优,逼近最优解。通过调整参数和策略,SA通常能获得比贪心算法更好的结果,但计算时间较长。
最低0.47元/天 解锁文章
1011

被折叠的 条评论
为什么被折叠?



