程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2023-01(4)

2023-02(5)

第十四届华中杯大学生数学建模挑战赛A题Python解答共51批(附文件源码链接)需者自取

发布于2022-08-07 20:49     阅读(1033)     评论(0)     点赞(16)     收藏(3)


问题重述:

A 分拣系统优化问题
某电商公司配送中心的工作流程分为统计汇总、转运上架、按订单分拣、核对打包等
步骤。其中,分拣环节操作复杂,耗时较长,其效率是影响配送中心整体性能的关键因素。
首先,系统统计汇总出当天全部待配送订单所包含的所有货品及相应数量。然后,转运工
将这些货品由仓库转运至分拣处,并放置到货架上,等待分拣。上架时,一个货架中仅放
置同一种货品。为简化问题,不考虑货架的容积和载重限制,即每个货架能够放置的货品
件数没有限制。最后,分拣工按任务单依次分拣出每一个订单包含的货品。
例如,某天共有 5 个订单,订单的信息如表 1 (原始数据文件格式见附件 1 格式说明)
所示。
1 :订单信息示例
订单编号
所含货品种类及相应数量
D0001
P0001 × 2, P0002 × 1, P0003 × 1, P0004 × 1
D0002
P0003 × 1, P0004 × 1, P0005 × 1, P0006 × 3
D0003
P0001 × 1, P0003 × 1, P0005 × 1, P0007 × 1
D0004
P0002 × 1, P0004 × 1, P0006 × 1, P0008 × 3
D0005
P0001 × 1, P0003 × 2, P0004 × 1, P0007 × 1
系统统计出这 5 个订单共包含 8 26 件货品,分别为 4 P0001 2 P0002 5
P0003 4 P0004 2 P0005 4 P0006 2 P0007 3 P0008 。转运工将这些货
品分别放置在 8 个货架上。分拣工根据任务单上的订单信息,依次分拣出每一个订单的货
品。
随着该公司业务量不断增长,未来有可能出现当天待配送订单所含货品种类数大于当
前货架数量
的情况(假设任何一个订单所含货品种类数均小于货架数量
)。但是,
由于受到场地和成本的限制,很难直接增加货架。该公司希望在你们团队的协助下解决该
问题,并尝试提高分拣效率。具体解决如下问题。
1. 设计分批算法 :将当日订单分为多个批次。要求每个批次的订单所含货品种类数均不
超过
,且批次越少越好(相应转运次数也越少,效率越高)。针对附件 1 中的订单
信息,应用你们的算法,计算当货架数量
时最少的批次数,给出每批订单数
量、货品种类数、分批方案等结果,并将完整原始分批方案按指定格式输出到文件
result1.csv 中,格式要求见附件 2

问题一解题思路(其他思路在链接里)

第一步:根据附件的订单信息,提取每个订单的货品种类数存入列表df_pv_list中,提取每个订单的编号存入列表orderno_list中,这两个列表中的元素个数一致,且每个订单编号对应的货品种类数在两个列表中的索引一致。例如,列表df_pv_list的第一个元素df_pv_list[0] =’D0001’对应的货品种类数,应为列表orderno_list的第一个元素orderno_list[0]=19种,即两个列表的索引值相互关联或者说完全一一对应。

第二步:根据附件的订单信息,创建一个‘键’由订单号组成,‘值’由订单号对应的的货品种类列表组成的字典dic。

第三步:从列表df_pv_list中获取一个最大值,即max_values = max(df_pv_list),通过index()方法得到max_values对应的索引值,即index_values = df_pv_list.index(max_values),由于列表df_pv_list与列表orderno_list的索引值相对应,可以得到对应的订单编号orderno_max = orderno_list[index_values]。由订单编号orderno_max从字典dic中获取该订单编号对应的货品种类依次存入batch_s列表中,并统计其中货品种类个数n。

第四步:用pop()方法将max_values从列表df_pv_list中移除,即df_pv_list.pop(index_values),由于在列表df_pv_list中max_values可能不止一个,为了保证列表df_pv_list和列表orderno_list元素严格一一对应,此处移除只能用pop()方法,根据索引值去移除元素。再将订单编号orderno_max从列表orderno_list中移除,即orderno_list.remove(orderno_max),此处移除操作可以使用remove()方法,因为列表orderno_list中的元素唯一,可以根据值去移除。

第五步:使用循环逐个从列表orderno_list取出订单编号,将取出来的订单编号作为‘键’从字典dic中得到每个订单对应的货品种类列表,再嵌套循环将每个订单对应的货品种类列表里的每个元素与列表batch_s里的每个元素相比较,设置计数器count,表示每个订单对应的货品种类与列表batch_s里的货品种类相同的件数。如果有相等的元素对count进行加1操作。将所有count值存入列表num_com中,注意:列表df_pv_list,列表orderno_list与列表num_com的数据是严格一一对应的,即相同索引从三个列表取的值是一一对应的。

第六步:判断n是否小于200,若是,则获取最大货品相同的件数max_num_com = max(num_com),获取对应的索引max_num_com_index = num_comt.index(max_num_com),获取对应的订单编号orderno_m = orderno_list[max_num_com_index],将获取的订单编号作为‘键’从字典dic中得到每个订单对应的货品种类列表,求其列表长度得到货品种类数num,用货品种类数num减去列表num_com对应的货品相同件数得到不相同件数,即num_none = num - num_com[max_num_com_index],并将该货品列表里的每个元素与batch_s列表中的元素一一比较,将不同的元素加入进batch_s列表中,再重新统计batch_s列表中的货品种数n。

第七步:创建批次列表batch_list(在第四步,执行移除操作之前应将订单orderno_max添加到该列表中)。将max_values赋给n,比较n是否小于200,若小于,将订单编号存入列表batch_list中,即batch_list.append(orderno_m),执行n =n +num_none操作。再将列表df_pv_list中对应的值移除,即df_pv_list.pop(max_num_com_index),将列表orderno_list中对应的值移除,即orderno_list.remove(orderno_m),将列表num_com设置为空;重复第五步至第七步操作直到n大于等于200;若大于,批次操作完成,打印出batch_list列表信息,将列表num_com设置为空,将列表batch_s设置为空,重复执行第三步至第七步操作。每次重复执行第三步至第七步操作时,都需判断列表df_pv_list和列表orderno_list列表是否为空。若为空,则所有订单都已处理完成,将保存在列表batch_list中的数据依批次打印出来即可,再将其输出至result1.csv文件中。否则继续执行重复操作。

分批算法Python实现:

创建每个订单的货品种类数量列表df_pv_list

创建每个订单编号列表orderno_list

创建每个订单与之对应的货品种类列表的字典dic

创建每批次列表batch_list

创建总批次列表sum_batch_list

创建每批次货品种类数列表batch_s

创建总批次货品种类数列表sum_batch_s

创建订单的货品种类的相同数列表num_com

  1. 定义getMax_per_batch_info(n)方法,有1个形参,用来传入每批货品种类的值n。该方法的功能为经计算后返回列表batch_s货品种类数和batch_s货品列表,共返回两个值。
  2. 定义get_num_com(i_l_m)方法,有1个形参,分别以getMax_per_bath_info()方法返回的batch_s值作为实参传入。该方法功能为计算其他订单与batch_s列表中货品种类相同的件数,并将其结果存入num_com列表中。
  3. 定义get_bath_info(n,num_com)方法,有2个形参,将getMax_per_batch_info(n)方法的返回值n作为实参传入。该方法有2个while循环,判断n是否小于200,若小于,则将最大相同件数订单的货品种类不存在于batch_s列表中货品种类依次存入batch_s列表中,判断batch_s列表长度是否大于200,若大于,跳出循环;若小于,则继续调用getMax_per_batch_info(n)方法和get_num_com(i_l_m)方法;直至列表batch_s中货品种类数等于200,循环结束。输出批次信息并保存至batch_list列表中,并将已经处理的订单从列表orderno_list列表中移除。

        4、主程序为利用for循环调用以上三个方法,每循环1次应得到1个批次结果,将每次循环得到的结果存入sun_bacth_list列表中,最后将最终结果转换为DataFrame结构数据,输入到result1.csv文件中。应有判断语句,判断orderno_list列表是否为空,若为空,则结束程序;否则,继续执行。、

python代码如下:

  1. '''
  2. 设计分批算法:将当日订单分为多个批次。要求每个批次的订单所含货品种类数均不
  3. 超过 ,且批次越少越好(相应转运次数也越少,效率越高)。针对附件 1 中的订单
  4. 信息,应用你们的算法,计算当货架数量 时最少的批次数,给出每批订单数
  5. 量、货品种类数、分批方案等结果,并将完整原始分批方案按指定格式输出到文件
  6. result1.csv 中
  7. '''
  8. import pandas as pd
  9. #将数据读取进来
  10. df = pd.read_csv(r'D:\Pycharm\pythonProject\data.csv')
  11. #将原始数据csv文件处理一下,生存OrderNoSum.csv(已放入了附件中),用来获取每个订单编号
  12. df1 = pd.read_csv(r'D:\Pycharm\pythonProject\OrderNoSum.csv')
  13. orderno_list = []
  14. for i in df1['OrderNo'].values:
  15. orderno_list.append(i)
  16. #统计每个订单的货品种类数量
  17. df_pv = df.groupby('OrderNo')['ItemNo'].count()
  18. #将每个订单的货品种类数量存入列表中
  19. df_pv_list=[] #923个值
  20. for i in df_pv.values:
  21. df_pv_list.append(i)
  22. #获取每个订单货品的编号与其种类数量相对
  23. itemno_list = df['ItemNo'].values
  24. #将每个订单的货品种类改成键值对的形式
  25. dic = {}
  26. sum_x = 0
  27. dic.setdefault('{}'.format(orderno_list[0]),'{}'.format(list(itemno_list[0:df_pv_list[0]])))
  28. for i in range(1,923):
  29. sum_x = sum_x + df_pv_list[i-1]
  30. dic.setdefault('{}'.format(orderno_list[i]),'{}'.format(list(itemno_list[sum_x:(sum_x+df_pv_list[i])])))
  31. #每批次订单所含货品种类数列表
  32. def getMax_per_batch_info(n):
  33. if df_pv_list == []:
  34. print('df_pv_list为空,数据已全部处理。')
  35. if orderno_list == []:
  36. print('orderno_list为空,订单已全部处理。')
  37. return
  38. #获取货品种类数最大的值
  39. if batch_s == []:
  40. max_values = max(df_pv_list)
  41. #df_pv_list.remove(max_values)
  42. # #获取货品种类数最大的值的索引
  43. index_values = df_pv_list.index(max_values)
  44. # #获取订单编号
  45. orderno_max = orderno_list[index_values]
  46. #将订单编号放入批次列表中
  47. batch_list.append(orderno_max)
  48. # #从dic中获取订单对应的货品
  49. item_list_max = eval(dic[orderno_max])
  50. #将货品加入每批次订单所含货品种类数列表
  51. for i in item_list_max:
  52. if i in batch_s:
  53. n=n
  54. else:
  55. batch_s.append(i)
  56. n=n+1
  57. df_pv_list.pop(index_values)
  58. orderno_list.remove(orderno_max)
  59. else:
  60. n = n
  61. return [batch_s,n]
  62. def get_num_com(i_l_m):
  63. for x in orderno_list:
  64. count = 0
  65. for j in eval(dic[x]):
  66. for i in i_l_m:
  67. if j == i:
  68. count = count + 1
  69. break
  70. num_com.append(count)
  71. return num_com
  72. def get_batch_info(n,num_com):
  73. while n < N:
  74. max_num_com = max(num_com)
  75. #获取最大重叠率的索引
  76. max_num_com_index = num_com.index(max_num_com)
  77. #获取最大相同种类数的的订单编号
  78. orderno_m = orderno_list[max_num_com_index]
  79. num = len(eval(dic[orderno_m]))
  80. #非重叠货品种类数量
  81. num_com_num = num_com[max_num_com_index]
  82. num_none = num - num_com[max_num_com_index]
  83. #批次总的货品种类数(不能大于200)
  84. n = n + num_none
  85. #print(n)
  86. while n > N:
  87. #print('n>N')
  88. orderno_list_copy = orderno_list[:]
  89. while True:
  90. n = n - num_none
  91. orderno_list_copy.remove(orderno_m)
  92. num_com.pop(max_num_com_index)
  93. if num_com == []:
  94. break
  95. max_num_com = max(num_com)
  96. max_num_com_index = num_com.index(max_num_com)
  97. orderno_m = orderno_list_copy[max_num_com_index]
  98. num = len(eval(dic[orderno_m]))
  99. num_com_num = num_com[max_num_com_index]
  100. num_none = num - num_com[max_num_com_index]
  101. n = n + num_none
  102. if n>N:
  103. orderno_list_copy = orderno_list_copy[:]
  104. continue
  105. else:
  106. break
  107. break
  108. if num_com == []:
  109. break
  110. else:
  111. # 将货品加入列表中
  112. for i in eval(dic[orderno_m]):
  113. if i in batch_s:
  114. continue
  115. else:
  116. batch_s.append(i)
  117. # 将订单编号放入批次列表中
  118. batch_list.append(orderno_m)
  119. df_pv_list.pop(max_num_com_index)
  120. orderno_list.remove(orderno_m)
  121. break
  122. return n
  123. #主程序
  124. sum_batch_s =[]
  125. # 相同货品种类数列表
  126. num_com = []
  127. #批次列表
  128. batch_list = []
  129. #总的批次列表
  130. sum_batch_list = []
  131. N = 200
  132. for i in range(1,80):
  133. if df_pv_list == []:
  134. if orderno_list == []:
  135. break
  136. # 每批次订单所含货品种类数列表
  137. batch_list = []
  138. num_com = []
  139. batch_s = []
  140. n=0
  141. arg_list = getMax_per_batch_info(n)
  142. if arg_list == None:
  143. print('数据已全部处理。')
  144. break
  145. else:
  146. b=get_num_com(arg_list[0])
  147. n = get_batch_info(arg_list[1],b)
  148. while True:
  149. num_com = []
  150. arg_list = getMax_per_batch_info(n)
  151. if arg_list == None:
  152. sum_batch_list.append(batch_list)
  153. sum_batch_s.append(batch_s)
  154. print('数据已全部处理。')
  155. break
  156. else:
  157. b = get_num_com(arg_list[0])
  158. n = get_batch_info(arg_list[1], b)
  159. if n < N:
  160. continue
  161. else:
  162. sum_batch_list.append(batch_list)
  163. sum_batch_s.append(batch_s)
  164. break
  165. print('正在统计最终结果,请稍等片刻。。。。。。。。。。')
  166. OrderNo_list = []
  167. GroupNo_list = []
  168. for i in range(0,51):
  169. for j in sum_batch_list[i]:
  170. OrderNo_list.append(j)
  171. GroupNo_list.append(i+1)
  172. #保存数据
  173. result1_dic = {'OrderNo':OrderNo_list,
  174. 'GroupNo':GroupNo_list}
  175. result1_df = pd.DataFrame(result1_dic,index=None)
  176. result1_df.reset_index(drop=True)
  177. result1_df.to_csv(r'D:\Pycharm\pythonProject\result1.csv')
  178. print('第一问给出结果如下:')
  179. for i in range(51):
  180. print('第{}批订单数为:'.format(i+1),len(sum_batch_list[i]),'货品种类数为:',len(sum_batch_s[i]))
  181. print('分批方案为:',sum_batch_list[i])
  182. print('----------------------------------------------------------------')
  183. print()
  184. print('总批数:',len(sum_batch_s))
  185. print()
  186. print('result1.csv文件已生成')
  187. print('程序到此结束')

部分运行结果:

第1批订单数为: 22 货品种类数为: 200
分批方案为: ['D0148', 'D0613', 'D0674', 'D0246', 'D0726', 'D0337', 'D0497', 'D0581', 'D0601', 'D0391', 'D0352', 'D0630', 'D0747', 'D0912', 'D0294', 'D0496', 'D0423', 'D0539', 'D0776', 'D0384', 'D0903', 'D0210']
----------------------------------------------------------------

第2批订单数为: 8 货品种类数为: 200
分批方案为: ['D0189', 'D0233', 'D0149', 'D0164', 'D0211', 'D0270', 'D0036', 'D0106']
----------------------------------------------------------------

第3批订单数为: 20 货品种类数为: 200
分批方案为: ['D0174', 'D0089', 'D0218', 'D0580', 'D0466', 'D0426', 'D0281', 'D0443', 'D0403', 'D0513', 'D0375', 'D0784', 'D0868', 'D0906', 'D0488', 'D0764', 'D0861', 'D0490', 'D0234', 'D0646']
----------------------------------------------------------------

第4批订单数为: 20 货品种类数为: 200
分批方案为: ['D0145', 'D0409', 'D0468', 'D0190', 'D0320', 'D0670', 'D0505', 'D0882', 'D0474', 'D0413', 'D0591', 'D0540', 'D0498', 'D0572', 'D0825', 'D0486', 'D0612', 'D0433', 'D0401', 'D0116']
----------------------------------------------------------------

第5批订单数为: 10 货品种类数为: 200
分批方案为: ['D0203', 'D0708', 'D0412', 'D0187', 'D0769', 'D0117', 'D0717', 'D0232', 'D0766', 'D0102']
----------------------------------------------------------------

第6批订单数为: 13 货品种类数为: 200
分批方案为: ['D0028', 'D0046', 'D0707', 'D0815', 'D0259', 'D0898', 'D0870', 'D0173', 'D0705', 'D0219', 'D0178', 'D0381', 'D0354']
----------------------------------------------------------------

第7批订单数为: 6 货品种类数为: 200
分批方案为: ['D0283', 'D0458', 'D0006', 'D0744', 'D0553', 'D0063']
----------------------------------------------------------------

第8批订单数为: 30 货品种类数为: 200
分批方案为: ['D0133', 'D0767', 'D0481', 'D0741', 'D0060', 'D0194', 'D0678', 'D0340', 'D0142', 'D0147', 'D0397', 'D0792', 'D0891', 'D0894', 'D0475', 'D0899', 'D0386', 'D0851', 'D0830', 'D0399', 'D0878', 'D0166', 'D0460', 'D0544', 'D0042', 'D0019', 'D0043', 'D0550', 'D0800', 'D0078']
----------------------------------------------------------------
 

注意:代码里面的data.csv文件为官网上题目里的附带文件,我改成了data,csv名字;OrderNoSum.csv文件是经过data.csv文件处理的文件,将它与data.csv放在同一目录下。

第1问至第3问相关文件和源码放这了:

链接:https://pan.baidu.com/s/11UBm1LPLgAANu-nixi9KEQ 
提取码:4859

答案不一定准确,有错误或者不恰当的地方请指出!一起学习进步!!

原文链接:https://blog.csdn.net/m0_57903984/article/details/124865827



所属网站分类: 技术文章 > 博客

作者:hehrie83489

链接:https://www.pythonheidong.com/blog/article/1645181/08364fc4d63e05b604de/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

16 0
收藏该文
已收藏

评论内容:(最多支持255个字符)