当前位置: 首页 > news >正文

Capacitated Facility Location Problem

文章目录

  • Capacitated Facility Location Problem
    • [更多技术博客 http://vilins.top/](http://vilins.top/)
    • 题目
    • 分析
    • 实验工具
    • 解决算法
      • 模拟退火法
      • 禁忌搜索
    • 算法局部设计细节
      • 模拟退火法
      • 禁忌搜索
    • 结果整理
    • 两种做法的对比
    • 原始输出结果
    • 程序运行说明
    • 源码
    • github
    • [更多技术博客 http://vilins.top/](http://vilins.top/)

Capacitated Facility Location Problem

更多技术博客 http://vilins.top/

题目

分析

选址问题在生产生活,物流,甚至军事中都有这非常广泛的应用,以成为运筹学中经典的问题之一,其目的是确定一个或者多个设施的地址,使得判断标准获得优化的同时,及时向顾客提供其所需的产品和服务。工厂选址问题不仅影响到工厂的利润和市场竞争力,甚至决定了工厂的生死存亡。所以,工厂选址的研究具有重要意义。
这类问题在论文中出现得比较多,而网上现成的以实现的办法几乎没有,很多都是从理论层面上分析解决这类问题的可行性,而没有实操去证明其可行性。由于这类问题属于优化类问题,在线性时间很难求得其最优解,所以我们选择算法的时候一般选择优化类算法,动态规划之类的算法是行不通的,一般用于解决这类问题的办法有蚁群算法,遗传算法,贪婪算法,模拟退火法,禁忌搜索算法,近似算法等。
具体到这个题目,我们首先分析其限制的条件,这是一类有容量限制的工厂问题,具体限制如下:

总花费(total cost) = 工厂开放花费(opening cost) + 顾客分配到某个工厂以后的路程花费(assginment cost)

实验工具

语言:python
工具:Pycharm

解决算法

模拟退火法

禁忌搜索

算法局部设计细节

模拟退火法

初始解的产生,采用完全随机化选择部分工厂开放,但不让所有的工厂开放,符合一般最优化表现形式,表现最好。

def init_solution(self): for i in range(self.customer_num): self.current_state_of_customer.append(-1) for i in self.demand: self.total_demand += i self.current_capacity = self.capacity.copy() total_cost = 0 temp = [] while total_cost < self.total_demand: r = random.randint(0, self.facility_num - 1) if r not in temp: temp.append(r) total_cost += self.capacity[r] index = 0 for i in range(self.customer_num): if self.current_capacity[temp[index]] - self.demand[i] >= 0: self.current_capacity[temp[index]] -= self.demand[i] self.current_state_of_customer[i] = temp[index] else: index += 1 i -= 1 # self.current_state_of_customer[i] = index # self.current_capacity[index] -= self.demand[i] self.current_cost = self.calculate_cost(self.current_state_of_customer) self.new_capacity = self.current_capacity.copy() self.new_state_of_customer = self.current_state_of_customer.copy()

初始化解,利用局部贪婪,可以调节贪婪的比例,但效果不太好

def init_solution(self): for i in range(self.customer_num): self.current_state_of_customer.append(-1) for i in self.demand: self.total_demand += i self.current_capacity = self.capacity.copy() for i in range(self.customer_num): ran_select = random.random() if ran_select > 0.2: min = 100000 index = 0 for j in range(self.facility_num): if min > self.assignment[j][i]: min = self.assignment[j][i] index = j if self.current_capacity[index] >= self.demand[i]: self.current_capacity[index] -= self.demand[i] self.current_state_of_customer[i] = index else: tag = True while tag: ran = random.randint(0, self.facility_num - 1) if self.current_capacity[ran] >= self.demand[i]: self.current_capacity[ran] -= self.demand[i] self.current_state_of_customer[i] = ran tag = False else: tag_out = True while tag_out: ran = random.randint(0, self.facility_num - 1) if self.current_capacity[ran] >= self.demand[i]: self.current_capacity[ran] -= self.demand[i] self.current_state_of_customer[i] = ran tag_out = False self.current_cost = self.calculate_cost(self.current_state_of_customer) self.new_capacity = self.current_capacity.copy() self.new_state_of_customer = self.current_state_of_customer.copy() print('cost ', self.current_cost) print('current cap ', self.current_capacity) print('current cu ', self.current_state_of_customer)

产生新解的方式

def gen_new_solution(self): tag = True self.new_capacity = self.current_capacity.copy() self.new_state_of_customer = self.current_state_of_customer.copy() while tag: ran_customer = random.randint(0, self.customer_num - 1) ran_facility = random.randint(0, self.facility_num - 1) # print("ran ", ran_facility, ran_customer) if self.new_capacity[ran_facility] >= self.demand[ran_customer]: tag = False self.new_capacity[ran_facility] -= self.demand[ran_customer] origin = self.new_state_of_customer[ran_customer] self.new_state_of_customer[ran_customer] = ran_facility if origin == -1: break self.new_capacity[origin] += self.demand[ran_customer] else: continue

退火过程

def simulated_annealing(self): global fp_anneal time_start = time.time() while self.T > 0.01: i = 0 while i < self.repeat: i += 1 self.gen_new_solution() self.current_cost = self.calculate_cost(self.current_state_of_customer) new_cost = self.calculate_cost(self.new_state_of_customer) if new_cost < self.current_cost: self.current_capacity = self.new_capacity.copy() self.current_state_of_customer = self.new_state_of_customer.copy() # print("current cost ", new_cost) else: num = math.exp((self.current_cost - new_cost) / self.T) ran = random.random() # print("num ", num) # print("ran ", ran) if num >= ran: self.current_capacity = self.new_capacity.copy() self.current_state_of_customer = self.new_state_of_customer.copy() # print("current cost ", new_cost) self.T *= self.cooling_rate time_end = time.time() used_time = time_end - time_start fp_anneal.write('time ' + str(used_time) + '\n') fp_anneal.write('cost ' + str(self.current_cost) + '\n') temp = [] result_state = [] for i in range(self.customer_num): if self.current_state_of_customer[i] not in temp: temp.append(self.new_state_of_customer[i]) temp.sort() for i in range(self.facility_num): result_state.append(0) for i in temp: result_state[i] = 1 # print('cost ' + str(self.current_cost)) # print(result_state) # print(self.current_state_of_customer) # print(self.current_capacity) fp_anneal.write('facility state ' + str(result_state) + '\n') fp_anneal.write('current state of customer ' + str(self.current_state_of_customer) + '\n\n')

禁忌搜索

新解产生与模拟退火类似
邻居的产生

def gen_nei_solution(self): tag = True self.nei_capacity = self.current_capacity.copy() self.nei_state_of_customer = self.current_state_of_customer.copy() ran_customer = 0 origin = 0 while tag: ran_customer = random.randint(0, self.customer_num - 1) ran_facility = random.randint(0, self.facility_num - 1) # print("ran ", ran_facility, ran_customer) if self.nei_capacity[ran_facility] >= self.demand[ran_customer]: tag = False self.nei_capacity[ran_facility] -= self.demand[ran_customer] origin = self.nei_state_of_customer[ran_customer] self.nei_state_of_customer[ran_customer] = ran_facility if origin == -1: break self.nei_capacity[origin] += self.demand[ran_customer] else: continue return ran_customer, origin

禁忌搜索过程

def tabu_search(self): global fp_tabu self.nei_state_of_customer = self.current_state_of_customer.copy() self.nei_capacity = self.current_capacity.copy() # print(self.current_state_of_customer) # print(self.nei_capacity) self.tabu_list = [[0 for i in range(self.customer_num)]for i in range(self.facility_num)] # print(tabu_list) repeat = 30000 count = 0 nei_count = int(self.customer_num/4) best_solution_customer = self.current_state_of_customer.copy() best_solution_capacity = self.current_capacity.copy() best_cost = self.calculate_cost(best_solution_customer) time_start = time.time() while count < repeat: count += 1 i = nei_count self.gen_new_solution() new_cost = self.calculate_cost(self.new_state_of_customer) ran_customer = 0 origin = 0 while i > 1: i -= 1 ran_customer, origin = self.gen_nei_solution() nei_cost = self.calculate_cost(self.nei_state_of_customer) # print("nei ", nei_cost) # print("new ", new_cost) if nei_cost < new_cost: self.new_state_of_customer = self.nei_state_of_customer.copy() self.new_capacity = self.nei_capacity.copy() new_cost = nei_cost if new_cost < best_cost: # print("new ", new_cost) best_solution_customer = self.new_state_of_customer.copy() best_solution_capacity = self.new_capacity.copy() best_cost = new_cost if self.tabu_list[origin][ran_customer] < count: self.tabu_list[origin][ran_customer] = count + 20 self.current_state_of_customer = self.new_state_of_customer.copy() self.current_capacity = self.new_capacity.copy() time_end = time.time() used_time = time_end - time_start temp = [] result_state = [] for i in range(self.customer_num): if best_solution_customer[i] not in temp: temp.append(best_solution_customer[i]) temp.sort() for i in range(self.facility_num): result_state.append(0) for i in temp: result_state[i] = 1 fp_tabu.write('time ' + str(used_time) + '\n') fp_tabu.write('cost ' + str(best_cost) + '\n') fp_tabu.write('facility state ' + str(result_state) + '\n') fp_tabu.write('customer state ' + str(best_solution_customer) + '\n\n') print(best_cost) print(result_state) print(best_solution_customer) print(best_solution_capacity)

结果整理

fileresulttimeresulttime
模拟退火法模拟退火法禁忌搜索禁忌搜索
p190335.12332606315612889859.848682165145874
p280055.52882313728332579409.718816757202148
p393145.13923668861389296789.466161012649536
p4116285.307790279388428109549.69756555557251
p591315.344730377197266913710.06436276435852
p677815.39656233787536679079.97243070602417
p795775.525223731994629962510.066269397735596
p8114395.5332002639770511143310.113304615020752
p985934.83005332946777390318.910385608673096
p1076484.93875694274902377249.172668695449829
p1192265.14822697639465390628.851669073104858
p12110334.917876720428467102778.693775177001953
p1393125.169209718704224960410.038275718688965
p1471645.242977142333984820410.189182996749878
p1589645.441417932510376103359.89920711517334
p16119255.371662139892578124969.891655445098877
p1792785.45040369033813597959.87352442741394
p1877815.39055061340332826510.18008804321289
p1992675.236989974975586104089.878618240356445
p20117585.060497522354126125939.863529920578003
p2192954.85899639129638791039.683191061019897
p2277385.12528634071350180889.918416261672974
p2396545.08836030960083100709.597949266433716
p24112634.70444393157959118009.354219436645508
p251228112.8904881477355961358967.44565677642822
p261162313.5537416934967041125470.20729756355286
p271357413.0281190872192381337766.27394366264343
p281572913.245565891265871757267.49193954467773
p291351013.50685191154481368372.6292462348938
p301189413.906796693801881179772.82930493354797
p311482313.6664142608642581441272.44930481910706
p321773312.950354576110841670872.29048991203308
p331253612.9812731742858891234367.8763542175293
p341158213.5367550849914551114269.67934989929199
p351448713.4699332714080811309968.77509903907776
p361568813.1477956771850591732067.9144344329834
p371220012.650130748748781224867.00625324249268
p381128313.4859235286712651117067.53133893013
p391348013.1727778911590581286265.43386697769165
p401568213.0899877548217771556964.73360013961792
p4170088.108281373977661790624.470109462738037
p4269327.624598264694214631221.45367980003357
p4365296.635222673416138673317.159975051879883
p4472068.201093912124634819727.290011882781982
p4573847.414166450500488748921.240010738372803
p4661666.826710224151611720817.667112588882446
p4764348.080354928970337724925.64135766029358
p4862997.8948752880096436643822.5309157371521
p4963296.82571268081665676417.12479257583618
p5093138.6319098472595211088029.890727758407593
p5179138.980969190597534893931.077434062957764
p5293478.536164283752441972633.53241181373596
p5399469.4257862567901611114132.7076473236084
p5491788.4992961883544921056033.5239634513855
p5584659.157528400421143831832.04251146316528
p562271321.77771425247192423903144.6936798095703
p573358119.87682652473449730914142.13889384269714
p585650118.7248744964599646049138.9957413673401
p593273820.6597051620483438781140.89498019218445
p602320123.38042521476745624435128.45606589317322
p613144618.32096123695373529426122.40536570549011
p626351816.8770191669464138882126.1437463760376
p633202718.30001544952392634958120.8425030708313
p642334721.73286342620849624081118.14805221557617
p652848317.2887492179870632030115.24073910713196
p664080915.93437194824218838021116.89702320098877
p672990717.8990929126739529351125.08517384529114
p6
http://www.jsqmd.com/news/937562/

相关文章:

  • 3步快速上手:Cursor Pro永久免费破解方案终极指南
  • 51单片机+DS18B20温度报警器保姆级教程:从Proteus仿真到普中开发板烧录全流程
  • 别再折腾了!保姆级教程:在VMware Ubuntu虚拟机里调用Windows主机摄像头(含Cheese/FFmpeg测试)
  • 2026年5月口碑好的过滤器源头厂家怎么选择,过滤器/精密调压阀/气源过滤器/大流量气源处理器,过滤器直销厂家推荐 - 品牌推荐师
  • 基于BERT与CNN的智能交互装置:情绪分析与手势识别的软硬件实现
  • 告别YUV图片转换烦恼:在Ubuntu 22.04上从源码编译libjpeg-turbo 2.1.5的完整指南
  • WeFlow:重新定义前端开发工作流的技术架构与实践指南
  • w3x2lni:魔兽地图开发者的格式转换终极解决方案
  • ATmega328P烧录Bootloader总报错?别急着换芯片,先检查这个签名!
  • 7-Zip-zstd:当压缩工具遇见现代算法,你的文件处理体验将彻底改变
  • 私人AI Agent搭建:让人人都拥有自己的数字员工
  • 老硬盘迁移到新电脑无限重启?可能是Intel VMD在捣鬼,附PE下驱动注入完整流程
  • 目标检测框回归的“进化史”:从IOU到CIOU,我们到底在优化什么?(附PyTorch实现对比)
  • 别再傻傻重做U盘了!Win10安装报错install.wim,用一条DISM命令10分钟搞定
  • Tessy新手避坑指南:从零搭建单元测试工程,手把手搞定.c文件与.h文件链接
  • WuWa-Mod:鸣潮游戏模组全面解析与实战指南
  • Smithbox终极指南:从零开始掌握魂系游戏修改工具
  • AI工程师全景解析:岗位分类、核心职责与薪资体系
  • 保姆级教程:在Ubuntu 20.04上管理多版本CUDA(11.0/11.4/12.1),用软链接自由切换
  • 如何在5分钟内彻底改变你的macOS鼠标光标样式
  • 别再傻傻重做U盘了!Windows10安装报错0x8007000D,一招拆分install.wim搞定
  • Arduino步进电机DIY:从原理到实践,打造智能口红选择器
  • AI应用开发工程师全景详解:从技术内核、岗位实战到职业跃迁的完整指南
  • 从一次Python3软链接报错,聊聊Linux系统PATH与命令寻址的那些“坑”
  • 鸣潮自动化工具完整指南:如何快速配置游戏自动战斗与声骸刷取
  • 工业防爆监控技术解析:湖北地区防爆监控应用与选型指南
  • 3分钟掌握苹果平方字体:免费PingFangSC完整使用教程
  • 鸣潮自动化终极指南:如何用ok-ww实现智能挂机解放游戏时间
  • 基于MOSFET的LED流水灯制作:无稳态多谐振荡器电路详解
  • 超越简单测试:深入Griewank函数,看它如何‘刁难’粒子群算法(PSO)