同系列算法問題
問題
有n個作業(編號爲1~n)要在由兩臺機器M1和M2組成的流水線上完成加工。每個作業加工的順序都是先在M1上加工,然後在M2上加工。M1和M2加工作業i所需的時間分別爲ai和bi(1≤i≤n)。
流水作業調度問題要求確定這n個作業的最優加工順序,使得從第一個作業在機器M1上開始加工,到最後一個作業在機器M2上加工完成所需的時間最少。可以假定任何作業一旦開始加工,就不允許被中斷,直到該作業被完成,即非優先調度。
問題概述
背景條件:兩臺機器,分別爲機器1和機器2,多個作業,每個作業必須在機器1完成的基礎上,才能在機器2加工。根據機器和作業分別有以下結論:
結論1:針對機器,在作業未完成的條件下,機器1的狀態是連續工作,但機器2的狀態可以是空閒和工作;
結論2:針對作業,n個作業,則有n!種排列可能;
結論3:作業的加工時間,是最後一個作業在機器2上的完成時間。
分析問題
根據問題概述所得的3個結論,有以下需要實現:
1.需要獲得每個作業的在2臺機器上所需的工作時間
2.對每一種可能進行窮舉,以實現所有的可能
3.建立每一種可能的工作流程和時間計算模型
4.打印所有的可能,並對所有的可能所得的結果進行篩選,獲得最優結果
解決問題
根據前面的分析,具體化問題,假設題目如下:
對以上的幾點,其中1,2,4點:
1和4 只是簡單的邏輯處理,
2可以通過調用全排列函數進行實現,則有(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,1,2)、(3,2,1)共3!=6種可能;
在第3點中,需要建立計算模型:
定義兩個變量sum_m1,sum_m2,分別用於存儲機器1和機器2的工作記錄,
取其中一種可能(1,2,3),其中,作業1在M1的時間爲HK1_M1,在M2的時間爲HK1_M2,
定義兩個列表,f1和f2,f1[i],f2[i]分別代表作業i在機器1,機器2的完成的那刻的時間(時間刻度),以此類推;
情景模擬開始,有如下圖
將作業1投入到機器M1時,則sum_m1 = HK1_M1=2,f1[1]=2
根據之前結論,機器2有空閒和工作兩種狀態:
這裏是機器2是空閒的狀態,所以sum_m2=sum_m1+HK1_M2=3,f2[1]=3
但是如果機器2不是空閒的狀態的話,則需要等待,如下,當作業1在機器M1完成時,機器M2正在工作,所以需要等待
所以可以有以下結論:
當sum_m1>=sum_m2時,sum_m2=sum_m1+HK[i]_M2
否則,即機器2正在工作,已在機器M1完成的作業需要等待機器M2
sum_m2=sum_m2+HK[i]_M2,f2[i]=sum_m2
例如這裏:
當作業3完成時,
sum_m1=2,f1[3]=2,sum_m2=2+3=5,f2[3]=5
當作業1完成時:
sum_m1=2+2=4,f1[1]=4,
sum_m2=5>sum_m1=4,所以sum_m2=sum_m2+HK[1]_M2=6
之後也是如此處理
編程
編程流程以及數據類型選擇
題目條件的準備:
定義2個字典,用於存儲作業i的在機器M1和機器M2所需的時間
dict_a = {1:HK1_M1,2:HK2_M1,...,i:HKi_M1}
dict_b = {1:HK1_M2,2:HK2_M2,...,i:HKi_M2}
題目求解時的對象定義:
定義1個列表,用於存儲所有的作業排列可能;
選擇列表用於存儲每一個作業的在機器M1和M2的完成時的時間刻度
f1=['','',...,''] ,f2=['','',...,''],則f2列表的最後一個元素即是題目的答案
還有其它不再贅述
發現問題以及解決
最終實現
程序代碼:
#author:zhj
#time:19.11.24
#versions:1.0
#question:流水作業調度問題
#全排列函數
per_result = []
def PrintLst(lst):
for i in lst:
print(i,end=" ")
#find the more index
lst_index = []
def find_index(lst,ele):
for i in range(len(lst)):
if(lst[i] == ele):
lst_index.append(i)
def per(lst,s,e):
if s == e:
per_result.append(list(lst))
else:
for i in range(s,e):
lst[i],lst[s] = lst[s],lst[i]#試探
per(lst,s+1,e)#遞歸
lst[i],lst[s] = lst[s],lst[i]#回溯
result_tuple_f = []
def get_f1_f2(lst,dict_a,dict_b):
sum_m1 = 0
sum_m2 = 0
f1 = ['' for i in range(len(lst))]
f2 = ['' for i in range(len(lst))]
for i in range(len(lst)):
ele = lst[i]
sum_m1 += dict_a[ele]
f1[i] = sum_m1
if(sum_m2 <= sum_m1):
sum_m2 = sum_m1+dict_b[ele]
else:
sum_m2 = sum_m2+dict_b[ele]
f2[i] = sum_m2
tuple_f = (f1,f2)
result_tuple_f.append(tuple_f)
# lst_id = [1, 2, 3,4]
#get the args
num = input("請輸入作業的個數:")
lst_id = [i+1 for i in range(int(num))]
a = []
b = []
for i in range(int(num)):
print("請輸入作業{}在機器M1,M2需要的時間".format(i+1))
input_m1_time = eval(input("M1["+str(i+1)+"]="))
a.append(input_m1_time)
input_m2_time = eval(input("M2["+str(i+1)+"]="))
b.append(input_m2_time)
print("")
dict_a = dict(zip(lst_id,a))
dict_b = dict(zip(lst_id,b))
per(lst_id,0,len(lst_id))
#[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 2, 1], [3, 1, 2]]
#print(per_result)#success
for i in per_result:
#print(i)#success
get_f1_f2(i,dict_a,dict_b)
#[([2, 5, 7], [3, 6, 10]), ([2, 4, 7], [3, 7, 8]),
# ([3, 5, 7], [4, 6, 10]), ([3, 5, 7], [4, 8, 9]),
# ([2, 5, 7], [5, 6, 8]), ([2, 4, 7], [5, 6, 8])]
#print(result_tuple_f)#success
good_bestf = result_tuple_f[0][1][-1]#將第1個的bestf賦值給good_bestf
lst_bestf = []
print("求解過程:")
for i in range(len(result_tuple_f)):#per_result[i],result_tuple_f[i][1]
#print("\t一個解:bestf={},調度方案:{},f2:{}".format(result_tuple_f[i][1][-1],per_result[i],result_tuple_f[i][1]))
print("\t一個解:bestf=",end="")
print(result_tuple_f[i][1][-1],end=" ")
lst_bestf.append(result_tuple_f[i][1][-1])
print("調度方案:",end="")
PrintLst(per_result[i])
print("f2:",end=" ")
PrintLst(result_tuple_f[i][1])
print("")
if(good_bestf < result_tuple_f[i][1][-1]):
good_bestf = good_bestf
elif(good_bestf > result_tuple_f[i][1][-1]):
good_bestf=result_tuple_f[i][1][-1]
# else:
# good_lst = good_lst
print("求解結果:")
print("最少時間:",end="")
print(good_bestf)
#find the bestf index
find_index(lst_bestf,good_bestf)
# return
print("最優調度方案:有{}種,如下:".format(len(lst_index)))
it = 0
for i in lst_index:
it +=1
print("方案{}:".format(it))
PrintLst(per_result[i])
print(" ")
運行結果截圖:
總結
這道題的關鍵在於數學建模過程,即機器時間的計算。這道題目中,注意所求的最後的機器M2完成最後一個作業的時間刻度。
程序缺陷以及完善
大量的對象定義,既讓整個程序結構明瞭,但又讓整個程序顯得臃腫。在之後的解題中,會考慮使用第三方庫numpy進行解題
另外會在以後中,使用動態規劃法重新解決這一道題。
解題心路歷程
大量的對象,讓整個程序的結構可能有些複雜。但編寫過程還算流暢,難就難在數學建模,參考了很多博客,發現很多博客在數學建模過程中的邏輯是錯誤的,所以數學建模過程,花費的時間很多,也藉助了Excel表格工具進行建模。
本篇未完成,會抽出時間進行更新。如有更改,會在此列出
本篇已完成。——2019.12.27