華中杯 數學建模 A題簡單覆盤(附Python原始碼)
import random
import pandas as pd
import time
# 這裡定義一個全域性變數,用來表示最大的貨架數——即批次種類限制
N = 200
# 然後是寫一個函式,實現只儲存同一訂單對應的貨品種類
def big_and_small(choose0, order):
"""
該函式用於在未保留的訂單中劃分大訂單和小訂單,大訂單佔 1/3
:param choose0:
:param order:
:return:
"""
big1 = []
small0 = []
choose0 = dict(choose0)
# 選取的訂單字典,鍵是訂單號,值是種類數
choose_order = {}
for i1 in choose0:
if choose0[i1] == 0:
choose_order[i1] = len(order[i1])
# 將未被選的訂單字典排序
choose_order = sorted(choose_order.items(), key=lambda x: x[1])
new_len = len(choose_order)
# 計算大小分界的索引
mid_index = new_len * 2 // 3
index0 = 0
for i1 in choose_order:
if index0 < mid_index:
small0.append(i1[0])
else:
big1.append(i1[0])
index0 += 1
return big1, small0
# 寫一個函式判斷是否在當前批次
def is_in(batch, order):
"""
其實應該是得出新增訂單的新增貨品種類數
:param batch: 當前批訂單 , 內容是包含的貨品
:param order: 當前訂單,也是貨品
:return: 新增貨品種類數
"""
# 將批次和訂單都列表化
batch = list(batch)
order = list(order)
ans = 0
# 迴圈累加不在當前批次的貨品種類數
for o0 in order:
if o0 not in batch:
ans += 1
return ans
# 寫一個選取函式
def choose_batch(orders1, batch01, batch02, keys0):
"""
該函式用於在大訂單集或者小訂單集將這些訂單實現分批
引入洗牌演算法,將選取的訂單的順序進行打亂隨機
:param orders1: 訂單
:param batch01: 批次列表 1 ,儲存批次對應的訂單
:param batch02: 批次列表 2 ,儲存批次對應的貨品種類
:param keys0: 選取訂單的列表 , 內容是訂單號
:return: 返回選取加入後的批次 1 和 2
"""
# 寫一個洗牌演算法
# 先獲取選取訂單的長度
# keys_len = len(keys0)
# # 逆序遍歷選取列表
# # 透過交換隨機下標來實現將選取的訂單的順序洗牌
# for k in range(keys_len - 1, -1, -1):
# # 獲取隨機下標
# rindex = random.randint(0, k)
# # 交換位置
# temp = keys0[rindex]
# keys0[rindex] = keys0[k]
# keys0[k] = temp
batch1 = dict(batch01)
batch2 = dict(batch02)
# 獲取到當前最大批次數對應的下標
i0 = len(batch1) - 1
# 如果此時沒有,這需要置為 0
if i0 < 0:
i0 = 0
for key0 in keys0:
# 初始時需要建立批次
if i0 not in batch1:
batch1[i0] = []
batch2[i0] = []
add_type = -1
index0 = -1
flag = False
for j in range(i0 + 1):
if key0 in batch1[j]:
flag = True
break
at = is_in(batch2[j], orders[key0])
# 完全重合直接退出迴圈
if at == 0:
index0 = j
break
if (add_type < 0 or add_type >= at) and len(batch2[j]) + at <= N:
add_type = at
index0 = j
if flag:
continue
if index0 >= 0:
batch1[index0].append(key0)
for good in orders1[key0]:
if good not in batch2[index0]:
batch2[index0].append(good)
else:
i0 += 1
batch1[i0] = []
batch1[i0].append(key0)
batch2[i0] = orders1[key0]
return batch1, batch2
# 然後接下來寫一個從小訂單中選取
def choose_small(orders1, batch1, batch2, small1):
orders1 = dict(orders1)
keys = list(small1)
batch1 = dict(batch1)
batch2 = dict(batch2)
batch1, batch2 = choose_batch(orders1, batch1, batch2, keys)
return batch1, batch2
# 這個是在大的陣列中重新選取
def choose_big(big1, orders1, batch, batch2):
orders1 = dict(orders1)
keys = list(big1)
# 批次陣列有兩種,一種是儲存訂單,一種是儲存貨品
batch1 = dict(batch)
batch2 = dict(batch2)
batch1, batch2 = choose_batch(orders1, batch1, batch2, keys)
return batch1, batch2
# 然後寫一個迭代函式
def gen_ite(order, btch_1, btch_2):
"""
參考遺傳演算法的精英基因保留的思想,我們在迭代的過程中將批次中訂單數較多的保留,這裡每次選取 10% 的批次
然後需要將這些批次標記為已經選擇然後重新在為選取的訂單集劃分大小訂單
選取的批次可以直接新增在下一代的開頭
:param order: 訂單字典,訂單號對應相應的貨品種類
:param btch_1:
:param btch_2:
:return: 最終多次迭代後的結果
"""
btch_1 = dict(btch_1)
btch_2 = dict(btch_2)
for i0 in range(1):
# 先對批次的訂單數排序 —— 降序排序
btch = sorted(btch_1.items(), key=lambda x: len(x[1]), reverse=True)
btch_len = len(btch)
index0 = btch_len // 5
# 生成兩個新的字典,和 btch1 , 2 類似
bt1 = {}
bt2 = {}
# 先將精英保留
# 選擇字典
choose_0 = {}
for j in order.keys():
choose_0[j] = 0
for k in range(index0):
for o0 in btch_1[k][1]:
choose_0[o0] = 1
bt1[k] = btch_1[btch[k][0]]
bt2[k] = btch_2[btch[k][0]]
keys = []
for m in order.keys():
if choose[m] == 0:
keys.append(m)
# # 接下來劃分大小訂單
# big1, small1 = big_and_small(choose, orders)
# print('big: %d small: %d' % (len(big1), len(small1)))
# # 之後根據劃分的大小訂單在得到新的分批
# bt1, bt2 = choose_big(big1, orders, bt1, bt2)
# print(len(bt1), len(bt2))
# # bt1, bt2 = choose_small(orders, bt1, bt2, small1)
# # print(len(bt1), len(bt2))
bt1, bt2 = choose_batch(order, bt1, bt2, keys)
# 然後比較新舊分批的批數來更新批次
if len(bt1) < len(btch_1):
btch_1 = bt1
btch_2 = bt2
print(' 第 %d 次 , 批次數為 %d' % (i0 + 1, len(btch_1)))
le = 0
for bi in btch_1:
le += len(btch_1[bi])
print(le)
return btch_1, btch_2
# 寫一個計算距離的函式
def compute_dis(order, batch10, goods):
"""
:param order: 其實就是訂單集合,透過訂單可以知道需要的貨品
:param batch10: 批次下的訂單列表
:param goods: 當前批次下的貨物關於貨物列表的索引
:return: 返回距離和
"""
order = dict(order)
batch10 = list(batch10)
goods = dict(goods)
dis = 0
for bat in batch10:
index_max = -1
index_min = -1
for good in order[bat]:
if index_min == -1 and index_max == -1:
index_max = index_min = goods[good]
else:
index_max = max(index_max, goods[good])
index_min = min(index_min, goods[good])
dis += index_max - index_min
return dis
# 寫一個第二問的解決函式
def solution2(order, batch2, batch1):
batch1 = dict(batch1)
batch2 = dict(batch2)
order = dict(order)
pre_total = 0
ans = []
p = 0
total = 0
start0 = time.time()
for batch in batch2.items():
# 現在是對每一個批次
# 先建立貨物種類到下標對映 , 和下標到貨物的對映
good_to_index = {}
index_to_good = batch[1]
for index1 in range(len(index_to_good)):
good = index_to_good[index1]
good_to_index[good] = index1
dis = compute_dis(order, batch1[batch[0]], good_to_index)
print(' 當前第 %d 批原始距離為 %d' % (p + 1, dis))
pre_total += dis
for i0 in range(200000):
j = random.randint(0, len(index_to_good) - 1)
k = random.randint(0, len(index_to_good) - 1)
if j == k:
continue
# 獲取貨物資訊
good1, good2 = index_to_good[j], index_to_good[k]
# 先交換
temp = good_to_index[good1]
good_to_index[good1] = good_to_index[good2]
good_to_index[good2] = temp
if dis > compute_dis(order, batch1[batch[0]], good_to_index):
index_to_good[j], index_to_good[k] = good2, good1
dis = compute_dis(order, batch1[batch[0]], good_to_index)
else:
good_to_index[good1], good_to_index[good2] = good_to_index[good2], good_to_index[good1]
print(' 迭代後 第 %d 批原始距離為 %d' % (p + 1, dis))
total += dis
ans.append(index_to_good)
p += 1
print(' 原始距離 ', pre_total)
print(' 最終距離 ', total)
end0 = time.time()
print(' 時間消耗 ', end0 - start0)
return ans
# 找到訂單的起始點
def find_min_and_max_index(order_good, good_index):
order_good = list(order_good)
good_index = dict(good_index)
min_index = max_index = -1
for good_name in order_good:
if min_index == -1 and max_index == -1:
min_index = max_index = good_index[good_name]
continue
min_index = min(min_index, good_index[good_name])
max_index = max(max_index, good_index[good_name])
return min_index, min_index
def right_find(order, batch1, good_index, pos):
order = dict(order)
batch1 = list(batch1)
good_index = dict(good_index)
ans = ''
j = int(pos)
tar = j
for name in batch1:
i1, i2 = find_min_and_max_index(order[name], good_index)
if i1 >= pos and (j > i1 or j == pos):
j = i1
ans = name
tar = i2
return ans, tar
def left_find(order, batch1, good_index, pos):
order = dict(order)
batch1 = list(batch1)
good_index = dict(good_index)
ans = ''
j = pos
tar = j
for name in batch1:
i1, i2 = find_min_and_max_index(order[name], good_index)
if i1 <= pos and (j < i1 or j == pos):
j = i2
ans = name
tar = i1
return ans, tar
def find_people(distance):
"""
找工人函式
我們根據方向和工人所處的位置決定,選取哪個工人
:param distance: 距離陣列
:return: 返回工人的下標
"""
# 答案初始化為下標 0
ans = 0
distance = list(distance)
for i1 in range(1, len(distance)):
if distance[i1] < distance[ans]:
ans = i1
return ans
def solution3(order, batch1, batch2, n):
"""
該函式主要用於求解第三問
:param order: 訂單對應的貨品,字典物件
:param batch1: 分批好的訂單,批號對應的訂單
:param batch2: 分批好的訂單對應的貨品種類,批號對應的種類
:param n: 工人的數量
:return: 返回第三問需要的結果
"""
# 先將這些字典物件示例化,實現可變引數在函式內和外的分離
batch1 = dict(batch1)
order = dict(order)
batch2 = dict(batch2)
# 答案,用列表儲存,每一個其實也是列表,分別對應答案需要的答案
ans = []
peo_dis1 = [] # 用來計算每一批員工的總路程
total_dis0 = [] # 總距離
for i1 in range(n):
total_dis0.append(0)
# 我們遍歷批次
for i1 in batch1.keys():
# 例項化批次對應的訂單和貨品種類,這裡其實還是將其變為陣列的形式
bat_or = list(batch1[i1])
bat_go = list(batch2[i1])
# 貨品在該批次中對應的位置, 即貨架的位置
good_index = {}
# 遍歷一遍訂單和貨品種類,這裡的順序其實就是第二問求解的擺放順序
for ind in range(len(bat_go)):
# 先獲取當前的貨物
good = bat_go[ind]
# 利用字典的對映關係,設定貨物對應的擺放位置的關係
good_index[good] = ind
people = [] # 工人列表,用來儲存工人的位置
task = [] # 任務列表,用來儲存工人當前批乾的第幾個訂單
peo_dis0 = [] # 當前批的距離
# 先將這兩個列表都初始化為 0
for p in range(n):
people.append(0)
task.append(0)
peo_dis0.append(0)
# 當批次中的訂單還有的時候,需要進行分配
while len(bat_or) > 0:
# 我們可以先進行正向的尋找 , 先找當前最小的下標,同級優先按工人編號尋找
p = find_people(peo_dis0)
# 獲取當前工人的位置
pos = people[p]
# 然後在以當前工人位置為起點,向右尋找最近的訂單,並返回訂單號和訂單完成時工人的位置
name, next_pos = right_find(order, bat_or, good_index, pos)
# 如果找不到訂單,說明右邊沒有訂單了,需要逆向尋找
if name == '':
# 向當前位置最左邊找離最近的訂單
name, next_pos = left_find(order, bat_or, good_index, pos)
task[p] += 1 外匯跟單gendan5.com # 當前工人的任務數 + 1
temp = [name, i1 + 1, p + 1, task[p]] # 當前行的答案
ans.append(temp) # 將這一行的答案新增到最終答案中
bat_or.remove(name) # 將這個訂單從列表中移除
print(next_pos)
# 計算移動距離
dis = abs(pos - next_pos)
# 加和
peo_dis0[p] += dis
people[p] = next_pos
peo_dis1.append(peo_dis0)
for ik in range(n):
total_dis0[ik] += peo_dis0[ik]
# 返回答案
return ans, peo_dis1, total_dis0
if __name__ == "__main__":
start = time.time()
# 先寫一個檔案路徑
filepath = ' 附件 1 :訂單資訊 .csv'
# 先讀取檔案
# 使用 pandas 內建的讀取方式
df = pd.read_csv(filepath) # 將檔案讀取為一個 dataframe 格式
con = pd.DataFrame(df, columns=['OrderNo', 'ItemNo'])
orders = {}
for line in con.index:
if not con.iloc[line]['OrderNo'] in orders:
orders[con.iloc[line]['OrderNo']] = []
orders[con.iloc[line]['OrderNo']].append(con.iloc[line]['ItemNo'])
s = set(orders.keys())
print(len(s))
# 選取字典,表示對應訂單是否被選取
choose = {}
# 初始化為未被選取
for key in orders.keys():
choose[key] = 0
big, small = big_and_small(choose, orders)
print(len(big), len(small))
b1, b2 = choose_big(big, orders, {}, {})
b1, b2 = choose_small(orders, b1, b2, small)
end = time.time()
print(end - start)
print(len(b1), len(b2))
btch1, btch2 = dict(b1), dict(b2)
file = open('result1.csv', 'w+')
result1 = 'OrderNo,GroupNo\n'
for b in btch1.keys():
for o in btch1[b]:
result1 += o + ',' + str(b + 1) + '\n'
print(result1, file=file)
file.close()
ans2 = solution2(orders, batch1=btch1, batch2=btch2)
result2 = 'ItemNo,GroupNo,ShelfNo\n'
for index in btch2.keys():
btch2[index] = ans2[index]
for _i in range(len(ans2[index])):
result2 += ans2[index][_i] + ',' + str(index + 1) + ',' + str(_i + 1) + '\n'
file = open('result2.csv', 'w+')
print(result2, file=file)
file.close()
ans3, peo_dis, total_dis = solution3(orders, batch2=btch2, batch1=btch1, n=5)
result3 = 'OrderNo,GroupNo,WorkerNo,TaskNo\n'
for a in ans3:
for index in range(len(a)):
result3 += str(a[index])
if index + 1 < len(a):
result3 += ','
else:
result3 += '\n'
file = open('result3.csv', 'w+')
print(result3, file=file)
file.close()
result4 = ''
for b in peo_dis:
for index in range(len(b)):
result4 += str(b[index])
if index + 1 < len(b):
result4 += ','
else:
result4 += '\n'
file = open(' 員工路程,單批 .csv', 'w+')
print(result4, file=file)
file.close()
file = open(' 員工路徑總和 .csv', 'w+')
result4 = ''
for i in range(len(total_dis)):
result4 += str(total_dis[i])
if i + 1 < len(total_dis):
result4 += ','
else:
result4 += '\n'
print(result4, file=file)
file.close()
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946337/viewspace-2909701/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 2020“數維杯”國際大學生數學建模競賽賽題分析
- “華為杯”第十七屆中國研究生數學建模成績資料分析
- 數學建模習題7.3
- 數學建模習題7.7
- 數學建模習題7.10
- 數學建模習題8.4
- 數學建模習題3.2
- 數學建模習題3.3
- 數學建模習題6.4
- [譯] 機器學習可以建模簡單的數學函式嗎?機器學習函式
- Python小白的數學建模課-07 選址問題Python
- SimMIM:更簡單的掩碼影像建模
- Python小白的數學建模課-06 固定費用問題Python
- 用Python實現簡單的人臉識別,10分鐘搞定!(附原始碼)Python原始碼
- python數學建模作業5.4 5.5Python
- goc 學習:原始碼部署和簡單使用Go原始碼
- Python數學建模-01.新手必讀Python
- 用python手刃Leetcode(1):兩數之和【簡單題】PythonLeetCode
- 數學建模
- MediaScanner原始碼簡單分析原始碼
- ssh問題之覆盤
- 棋盤覆蓋問題
- Python數學建模-02.資料匯入Python
- 為UCI機器學習庫引入簡單直觀的Python API(附程式碼)機器學習PythonAPI
- Python小白的數學建模課-19.網路流優化問題Python優化
- 2020年數學建模國賽B題解題思路
- 數學建模例題2.19sorted()使用示例
- 2024年中國研究生數學建模競賽D題
- 2024年中國研究生數學建模競賽E題
- Python小白的數學建模課-04.整數規劃Python
- python簡單例題在哪找Python單例
- 數學建模例題2.17 匯入模組示例
- 數學建模例題2.20 enumerate()函式使用示例函式
- 數學建模例題2.23 過濾重複值
- 數學建模例題2.25 陣列生成示例1陣列
- 數學建模例題2.28 矩陣合併示例矩陣
- 數學建模例題例 2.29 矩陣分割示例矩陣
- 數學建模例題2.30 矩陣元素求和示例矩陣