【轉】2018年全國大學生數學建模大賽B題簡要分析(附代碼)


  今天早上跟學姐室友去復旦把論文答辯做掉了,雖然整個項目基本上是我承擔了主要的思路與代碼部分,但是今天答辯我跟室友竟然連一句有用的話都沒說出來,全場都靠學姐開場流暢地引入,臨場隨機應變,從而得以與答辯教授歡聚喜散。主要原因是教授竟然准確地問到了我代碼里一個細節卻相當致命的問題(是一個隨機初始化問題,我下面代碼部分會詳細提到),正好學姐室友都不是特別熟悉我的隨機初始化方法,我又不能當場跟他們兩個解釋這個隨機初始化的問題。我差點當場就要以“這樣隨機初始化能夠減少代碼量”這種蹩腳的理由跟教授爭辯了。好在姜還是老的辣,辯論隊隊長出身的學姐一頓 Speech Art 操作成功忽悠掉了兩位教授,最終兩位答辯教授還是認可了我們的模擬仿真方法[捂臉]。事后細想以后我成功也好,失敗也罷,恐怕也是成也言語,敗也言語。也許我確實能夠成為一個有能力的人,但是說話藝術確實是一門很大的學問。不過看我運氣一直這么差,大概率還是凡人一個落入俗套吧[攤手]。

  言歸正傳,本文主要介紹我們小組解決2018年全國大學生B題的思路分析,不代表標准答案。當然我還是有自知之明,本身水平不是很高,再加上三天時間限制,自己做出來的模型以及算法肯定是比較差的。這里僅僅從我個人的思考角度出發寫一些參考思路作為分享討論,希望各位讀者朋友輕噴。

問題分析

  今年的B題確實與往年有很大的不同。往年的數學建模問題往往具有比較好的開放性,問題解決存在較大的建模空間。今年的B題的題干本身就幾乎是一個明確的模型(8台CNC+1台RGV+CNC定址),加上第二道任務要求我們根據給定三組數據完成八小時內的RGV詳細調度方案,並寫入四張Excel表格,給人的感覺就是要求我們去完成一道填空題,然后附帶寫一篇論文[尷尬]。

  為了方便各位讀者對賽題的閱讀,這里給出鏈接:https://download.csdn.net/download/cy19980216/10708725

  問題一共有四種不同的情況:一道工序無故障,一道工序有故障,兩道工序無故障,兩道工序有故障。

一道工序無故障

  第一種情況是最簡單的,直觀上直接不停地1234567812345678……按順序上料差不多就是最優了。但嚴謹地來說,雖然題目中給的三組數據確實都是用這種最幼稚的策略能夠達到最優,但是如果對於一般的情況而言,比如最極端的情況下,RGV移動時間無窮大,那RGV顯然就只會不停地在121212121212……這樣原地上下料了。

  然而我們發現無論參數怎么變化,最終RGV給CNC上下料的過程始終是一個周期性過程。當然這個似乎很“顯然”的事實卻是相當難以通過數學嚴格證明的(參數已知的情況下一般比較容易證明,但是所有的參數都是未知的情況下是很難嚴格說明的)。我賽后也仔細的思考過,但是也沒有得出很漂亮的證明。我最終僅僅是針對給定的三組數據使用了遺傳算法對RGV前17次上下料(17次是考慮從初始狀態開始循環兩圈的最短路徑)的最優路徑進行了搜索,並且利用窮舉證明了這是前17步最優的上下料次序。之后基本上就是不斷地循環。

  這里的模擬退火遺傳算法比較雞肋,所以我不詳細說明,在第三種情況我會詳細說明模擬退火遺傳算法的原理。

  以下給出第一種情況的模擬退火遺傳算法算法以及對應的窮舉最優證明 ↓↓↓

  1 # -*- coding:UTF-8 -*-
  2 """
  3     作者:囚生CY
  4     平台:CSDN
  5     時間:2018/10/09
  6     轉載請注明原作者
  7     創作不易,僅供分享
  8 """
  9  
 10 import math
 11 import random
 12 import itertools
 13  
 14 """ 選取一組數據 """
 15 T = 580
 16 d1 = 23
 17 d2 = 41
 18 d3 = 59
 19 Te = 35
 20 To = 30
 21 Tc = 30
 22  
 23 CNCT = [To,Te,To,Te,To,Te,To,Te]                                         # CNC上下料時間
 24  
 25 N = 50
 26 L = 17
 27  
 28 varP = 0.1
 29 croP = 0.6
 30  
 31 croL = 4
 32 e = 0.99
 33  
 34 tm = [
 35     [0,0,d1,d1,d2,d2,d3,d3],
 36     [0,0,d1,d1,d2,d2,d3,d3],
 37     [d1,d1,0,0,d1,d1,d2,d2],
 38     [d1,d1,0,0,d1,d1,d2,d2],
 39     [d2,d2,d1,d1,0,0,d1,d1],
 40     [d2,d2,d1,d1,0,0,d1,d1],
 41     [d3,d3,d2,d2,d1,d1,0,0],
 42     [d3,d3,d2,d2,d1,d1,0,0],
 43 ]
 44  
 45 def update_state(state,t):
 46     length = len(state)
 47     for i in range(length):
 48         if state[i] < t:
 49             state[i] = 0
 50         else:
 51             state[i] -= t
 52     return state
 53  
 54 def time_calc(seq):
 55     state = [0 for i in range(8)]                                           # 記錄CNC狀態
 56     isEmpty = [1 for i in range(8)]                                         # CNC是否為空?
 57     currP = 0
 58     total = 0
 59     length = len(seq)
 60     for No in seq:
 61         nextP = No
 62         t = tm[currP][nextP]
 63         total += t                                                         # rgv移動
 64         state = update_state(state,t)                                     # 更新state
 65         if state[No]==0:                                                 # 表明CNC等待
 66             if isEmpty[No]:                                                 # 當前CNC空
 67                 t = CNCT[No]
 68                 isEmpty[No] = 0
 69             else:
 70                 t = CNCT[No]+Tc
 71             total += t
 72             state = update_state(state,t)
 73             state[No] = T
 74         else:                                                             # 當前CNC忙
 75             total += state[No]                                             # 先等當前CNC結束
 76             state = update_state(state,state[No])                         
 77             t = CNCT[No]+Tc
 78             total += t
 79             state = update_state(state,t)
 80             state[No] = T
 81         currP = No
 82     total += tm[currP][0]
 83     return total
 84  
 85 def init_prob(sample):
 86     prob = []
 87     for seq in sample:
 88         prob.append(time_calc(seq))
 89     maxi = max(prob)
 90     prob = [maxi-prob[i]+1 for i in range(N)]
 91     temp = 0
 92     for p in prob:
 93         temp += p
 94     prob = [prob[i]/temp for i in range(N)]
 95     for i in range(1,len(prob)):
 96         prob[i] += prob[i-1]
 97     prob[-1] = 1                                                         # 精度有時候很出問題
 98     return prob
 99  
100 def minT_calc(sample):
101     minT = time_calc(sample[0])
102     index = 0
103     for i in range(1,len(sample)):
104         t = time_calc(sample[i])
105         if t < minT:
106             index = i
107             minT = t
108     return minT,index
109     
110 def init():
111     sample = []
112     for i in range(N):
113         sample.append([])
114         for j in range(L):
115             sample[-1].append(random.randint(0,7))
116     return sample
117  
118 def select(sample,prob):                                                 # 選擇
119     sampleEX = []
120     for i in range(N):                                                     # 取出N個樣本
121         rand = random.random()
122         for j in range(len(prob)):
123             if rand<=prob[j]:
124                 sampleEX.append(sample[j])
125                 break
126     return sampleEX
127  
128 def cross(sample,i):                                                     # 交叉
129     for i in range(len(sample)-1):
130         for j in range(i,len(sample)):
131             rand = random.random()
132             if rand<=croP*(e**i):                                         # 執行交叉
133                 loc = random.randint(0,L-croL-1)
134                 temp1 = sample[i][loc:loc+croL]
135                 temp2 = sample[j][loc:loc+croL]
136                 for k in range(loc,loc+croL):
137                     sample[i][k] = temp2[k-loc]
138                     sample[j][k] = temp1[k-loc]
139     return sample
140         
141 def variance(sample,i):                                                     # 變異算子                                         
142     for i in range(len(sample)):
143         rand = random.random()
144         if rand<varP*(e**i):
145             rand1 = random.randint(0,L-1)
146             rand2 = random.randint(0,L-1)
147             temp = sample[i][rand1]
148             sample[i][rand1] = sample[i][rand2]
149             sample[i][rand2] = temp
150     return sample
151     
152 def main():
153     sample = init()
154     mini,index = minT_calc(sample)
155     best = sample[index][:]
156     print(best)
157     for i in range(10000):
158         print(i,'\t',minT_calc(sample),end="\t")
159         prob = init_prob(sample)
160         sample = select(sample,prob)
161         sample = cross(sample,i)
162         sample = variance(sample,i)
163         mi,index = minT_calc(sample)
164         if mi>mini and random.random()<e**i:                             # 精英保留策略
165             rand = random.randint(0,N-1)
166             sample[rand] = best[:]
167         mini,index = minT_calc(sample)
168         best = sample[index][:]
169         print(best)
170     print(sample)
171  
172 if __name__ == "__main__":
173     main1()
174     """ 窮舉搜索驗證 """
175     a = list(itertools.permutations([1,2,3,4,5,6,7],7))
176     ts = []
177     first = [0,1,2,3,4,5,6,7,0]
178     for i in a:
179         temp = first+list(i)
180         temp.append(0)
181         t = time_calc(temp)
182         ts.append(t)
183     print(min(ts))    
184     print(time_calc([0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0]))

一道工序有故障

這部分是學姐做的,學姐用了偏數學的思考方式,仍然從循環的角度去考慮,主要考慮故障發生是否會影響當前循環,是否需要建立新的循環。因此就沒有寫代碼處理問題了。具體的思路我確實不是很能講清楚。但是這里面有一個非常大的問題,就是如果出現多台CNC同時發生故障怎么辦。關於多台機器同時發生故障的概率,我們通過估算認為以給定的三組數據8小時內會出現這種特殊情況的可能性大約為30%。這個問題是我無法很好嚴格處理的(當然如果用貪心算法也就沒這么多事了)。

兩道工序無故障 & 兩道工序有故障
這兩個部分都是我來處理的,因為使用的方法大致相同,就並在一起說了。

兩道工序與一道工序最大的區別在於三點:

1、開始要處理CNC任務分配:分配給第一道工序幾台CNC,分配給第二道工序幾台CNC?具體怎么布局?

2、加工過程可能仍然是一個循環,但是這個循環將可能會非常的龐大以至於不可能直觀的看出來。

3、兩道工序的分配已經是一個嚴格的NP難問題了(即理論上無法在多項式時間內求得最優解)。

第一點我的想法很單純——窮舉,沒錯,就是窮舉,除了顯然不合適的分配方案外,其他方案都試一遍(雖然真的很蠢,但是我真的想不出到底能怎么辦了)

第二點因為不存在循環則使用遺傳算法需要設定一個相當長的染色體長度(我們設定的染色體是RGV為各台CNC上下料的次序,如果要考慮全過程的模擬退火遺傳算法,則染色體長度大約在300~400左右)。事實上我也嘗試了這個方法,結果從我寫完這個算法我開始跑,一直跑到比賽結束算法依舊沒有收斂[捂臉]。這里給出代碼僅供參考(各位朋友要是有好意見也可以提出) ↓↓↓

  1 # -*- coding:UTF-8 -*-
  2 """
  3     作者:囚生CY
  4     平台:CSDN
  5     時間:2018/10/09
  6     轉載請注明原作者
  7     創作不易,僅供分享
  8 """
  9 import random
 10  
 11 # 第1組
 12 """
 13 d1 = 20
 14 d2 = 33
 15 d3 = 46
 16 T1 = 400
 17 T2 = 378
 18 To = 28
 19 Te = 31
 20 Tc = 25
 21 """
 22  
 23 # 第2組
 24 """
 25 d1 = 23
 26 d2 = 41
 27 d3 = 59
 28 T1 = 280
 29 T2 = 500
 30 To = 30
 31 Te = 35
 32 Tc = 30
 33 """
 34  
 35 # 第3組
 36 d1 = 18
 37 d2 = 32
 38 d3 = 46
 39 T1 = 455
 40 T2 = 182
 41 To = 27
 42 Te = 32
 43 Tc = 25
 44  
 45 cncT = [To,Te,To,Te,To,Te,To,Te]
 46 tm = [
 47     [0,0,d1,d1,d2,d2,d3,d3],
 48     [0,0,d1,d1,d2,d2,d3,d3],
 49     [d1,d1,0,0,d1,d1,d2,d2],
 50     [d1,d1,0,0,d1,d1,d2,d2],
 51     [d2,d2,d1,d1,0,0,d1,d1],
 52     [d2,d2,d1,d1,0,0,d1,d1],
 53     [d3,d3,d2,d2,d1,d1,0,0],
 54     [d3,d3,d2,d2,d1,d1,0,0],
 55 ]
 56 Type = [1,0,1,0,1,0,0,0]                                                 # CNC刀具分類
 57  
 58 N = 64
 59 L = 100
 60 varP = 0.1
 61 croP = 0.6
 62 croL = 2
 63 e = 0.99
 64  
 65 def init_first_round():                                                     # 第一圈初始化(默認把所有第一道CNC按順序加滿再回到當前位置全部加滿)
 66     state = [0 for i in range(8)]                                           # 記錄CNC狀態(還剩多少秒結束,0表示空閑)
 67     isEmpty = [1 for i in range(8)]                                         # CNC是否為空
 68     rgv = 0                                                                 # rgv狀態(0表示空車,1表示載着半成品)
 69     currP = 0
 70     total = 0
 71     seq = []
 72     flag = False
 73     for i in range(len(Type)):
 74         if Type[i]==0:
 75             seq.append(i)
 76             flag = True
 77     currP = seq[0]
 78     seq.append(currP)
 79     rgv,currP,total = time_calc(seq,state,isEmpty,rgv,currP,total)
 80     return state,isEmpty,rgv,currP,total,seq
 81  
 82 def update(state,t):
 83     for i in range(len(state)):
 84         if state[i] < t:
 85             state[i] = 0
 86         else:
 87             state[i] -= t
 88  
 89 def time_calc(seq,state,isEmpty,rgv,currP,total):                         # 事實上sequence可能是無效的,所以可能需要
 90     index = 0
 91     temp = 0
 92     while index<len(seq):
 93         """ 先移動到下一個位置 """
 94         nextP = seq[index]
 95         t = tm[currP][nextP]
 96         total += t
 97         update(state,t)
 98         if Type[nextP]==0:                                                 # 如果下一個位置是第一道工作點
 99             if rgv==1:                                                     # 然而載着半成品
100                 seq.pop(index)                                             # 去掉這個元素並中止當次循環進入下一個循環
101                 continue                
102             if isEmpty[nextP]:                                             # 如果下一個位置是空的
103                 t = cncT[nextP]
104                 total += t
105                 update(state,t)
106                 state[nextP] = T1                                         # 更新當前的CNC狀態
107                 isEmpty[nextP] = 0                                         # 就不空閑了
108             else:                                                         # 如果沒有空閑
109                 if state[nextP] > 0:                                     # 如果還在工作就等待結束
110                     t = state[nextP]
111                     total += t
112                     update(state,t)
113                 t = cncT[nextP]                                             # 完成一次上下料
114                 total += t
115                 update(state,t)
116                 state[nextP] = T1
117                 rgv = 1
118         else:                                                             # 如果下一個位置是第二道工作點
119             if rgv==0:                                                     # 如果是個空車
120                 seq.pop(index)                                             # 刪除當前節點
121                 continue
122             if isEmpty[nextP]:                                             # 如果下一個位置是空的
123                 t = cncT[nextP]
124                 total += t
125                 update(state,t)
126                 state[nextP] = T2
127                 isEmpty[nextP] = 0    
128             else:                                                         # 如果沒有空閑
129                 if state[nextP] > 0:                                     # 如果還在工作就等待結束
130                     t = state[nextP]
131                     total += t
132                     update(state,t)
133                 t = cncT[nextP]+Tc
134                 total += t
135                 update(state,t)
136                 state[nextP] = T2
137             rgv = 0
138         currP = nextP
139         temp = total 
140         index += 1    
141     total += tm[currP][Type.index(0)]                                     # 最后歸零
142     return rgv,currP,total
143  
144 def init_prob(sample,state,isEmpty,rgv,currP,total):                     # 計算所有sample的
145     prob = []
146     for seq in sample:
147         t = time_calc(seq,state[:],isEmpty[:],rgv,currP,total)[-1]
148         prob.append(t)
149     maxi = max(prob)
150     prob = [maxi-prob[i]+1 for i in range(N)]
151     temp = 0
152     for p in prob:
153         temp += p
154     prob = [prob[i]/temp for i in range(N)]
155     for i in range(1,len(prob)):
156         prob[i] += prob[i-1]
157     prob[-1] = 1                                                         # 精度有時候很出問題
158     return prob
159  
160 def minT_calc(sample,state,isEmpty,rgv,currP,total):
161     minT = time_calc(sample[0],state[:],isEmpty[:],rgv,currP,total)[-1]
162     index = 0
163     for i in range(1,len(sample)):
164         t = time_calc(sample[i],state[:],isEmpty[:],rgv,currP,total)[-1]
165         if t < minT:
166             index = i
167             minT = t
168     return minT,index
169     
170 def init():                                                                 # 初始化種群(按照第二道工序,第一道工序,第二道工序,第一道工序順序排列即可)
171     sample = []
172     refer0 = []
173     refer1 = []
174     for i in range(8):
175         if Type[i]==0:
176             refer0.append(i)
177         else:
178             refer1.append(i)
179     for i in range(N):
180         sample.append([])
181         for j in range(L):
182             if j%2==0:
183                 sample[-1].append(refer1[random.randint(0,len(refer1)-1)])
184             else:
185                 sample[-1].append(refer0[random.randint(0,len(refer0)-1)])
186     return sample
187  
188 def select(sample,prob):                                                 # 選擇算子
189     sampleEX = []
190     for i in range(N):                                                     # 取出N個樣本
191         rand = random.random()
192         for j in range(len(prob)):
193             if rand<=prob[j]:
194                 sampleEX.append(sample[j])
195                 break
196     return sampleEX
197  
198 def cross(sample,i):                                                     # 交叉算子
199     for i in range(len(sample)-1):
200         for j in range(i,len(sample)):
201             rand = random.random()
202             if rand<=croP*(e**i):                                         # 執行交叉
203                 loc = random.randint(0,L-croL-1)
204                 temp1 = sample[i][loc:loc+croL]
205                 temp2 = sample[j][loc:loc+croL]
206                 for k in range(loc,loc+croL):
207                     sample[i][k] = temp2[k-loc]
208                     sample[j][k] = temp1[k-loc]
209     return sample
210         
211 def variance(sample,i):                                                     # 變異算子                                         
212     for i in range(len(sample)):
213         rand = random.random()
214         if rand<varP*(e**i):
215             rand1 = random.randint(0,L-1)
216             randTemp = random.randint(0,int(L/2)-1)
217             rand2 = 2*randTemp if rand1%2==0 else 2*randTemp+1
218             temp = sample[i][rand1]
219             sample[i][rand1] = sample[i][rand2]
220             sample[i][rand2] = temp
221     return sample
222  
223 if __name__ == "__main__":
224     state,isEmpty,rgv,currP,total,seq = init_first_round()
225     print(state,isEmpty,rgv,currP,total)
226     sample = init()
227     mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)    
228     best = sample[index][:]
229     for i in range(100000):
230         f = open("GA.txt","a")
231         tmin = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)[0]
232         f.write("{}\t{}\n".format(i,tmin))
233         print(i,"\t",tmin,end="\t")
234         prob = init_prob(sample,state[:],isEmpty[:],rgv,currP,total)
235         sample = select(sample,prob)
236         sample = cross(sample,i)
237         sample = variance(sample,i)
238         mi,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)
239         if mi>mini and random.random()<e**i:                             # 精英保留策略
240             rand = random.randint(0,N-1)
241             sample[rand] = best[:]
242         mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)
243         best = sample[index][:]
244         print(best)
245         f.close()
246     print(sample)

遺傳算法這條路被堵死后我一度陷入俗套,用最直接的貪心搞了一陣子,覺得用貪心算法(即考慮下一步的最優策略)實在是對不起這種比賽。然后我就變得——更貪心一點了。

我試圖去尋找接下來K步最優的策略,然后走一步。K=1時算法退化為貪心算法,最終我們設置為K=4(當K>=8時算法速度已經相當緩慢,而4~7的結果大致相同,且K=4的速度基本可以做到2秒內得到結果)。

值得注意的是我假設RGV在兩道工序下只能由第一道工序的CNC到第二道工序的CNC(忽略清洗時間情況下),然后回到第一道工序的CNC,這樣往復移動(這里我不說明為什么一定要這樣,但是我認為確實應該是這樣)。在這個規律的引導下我大大減縮了代碼量以及計算復雜度。

然后到第四種情況我們已經沒有多余時間了,只能延續使用情況三的算法,進行了隨機模擬的修改,完成了第四種情況的填表。

以下是第三種情況的代碼(第四種類似就不上傳了)↓↓↓

  1 #coding=gbk
  2 import random
  3 # -*- coding:UTF-8 -*-
  4 """
  5     作者:囚生CY
  6     平台:CSDN
  7     時間:2018/10/09
  8     轉載請注明原作者
  9     創作不易,僅供分享
 10 """
 11 from tranToXls import *
 12  
 13 # 第1組
 14 """
 15 d1 = 20
 16 d2 = 33
 17 d3 = 46
 18 T1 = 400
 19 T2 = 378
 20 To = 28
 21 Te = 31
 22 Tc = 25
 23 """
 24 # 第2組
 25  
 26 d1 = 23
 27 d2 = 41
 28 d3 = 59
 29 T1 = 280
 30 T2 = 500
 31 To = 30
 32 Te = 35
 33 Tc = 30
 34  
 35  
 36 # 第3組
 37  
 38 """
 39 d1 = 18
 40 d2 = 32
 41 d3 = 46
 42 T1 = 455
 43 T2 = 182
 44 To = 27
 45 Te = 32
 46 Tc = 25
 47 """
 48  
 49 cncT = [To,Te,To,Te,To,Te,To,Te]
 50 tm = [
 51     [0,0,d1,d1,d2,d2,d3,d3],
 52     [0,0,d1,d1,d2,d2,d3,d3],
 53     [d1,d1,0,0,d1,d1,d2,d2],
 54     [d1,d1,0,0,d1,d1,d2,d2],
 55     [d2,d2,d1,d1,0,0,d1,d1],
 56     [d2,d2,d1,d1,0,0,d1,d1],
 57     [d3,d3,d2,d2,d1,d1,0,0],
 58     [d3,d3,d2,d2,d1,d1,0,0],
 59 ]
 60 Type = [0,1,0,1,1,1,0,1]                                                 # CNC刀具分類
 61  
 62 A = []                                                                     # 儲存第一道工序的CNC編號
 63 B = []                                                                     # 儲存第二道工序的CNC編號
 64 for i in range(len(Type)):
 65     if Type[i]:
 66         B.append(i)
 67     else:
 68         A.append(i)
 69  
 70 def init_first_round():                                                     # 第一圈初始化(默認把所有第一道CNC按順序加滿再回到當前位置全部加滿)
 71     state = [0 for i in range(8)]                                           # 記錄CNC狀態(還剩多少秒結束,0表示空閑)
 72     isEmpty = [1 for i in range(8)]                                         # CNC是否為空
 73     log = [0 for i in range(8)]                                             # 記錄每台CNC正在加工第幾件物料
 74     count1 = 0
 75     rgv = 0                                                                 # rgv狀態(0表示空車,1表示載着半成品)
 76     currP = 0
 77     total = 0
 78     seq = []
 79     flag = False
 80     for i in range(len(Type)):
 81         if Type[i]==0:
 82             seq.append(i)
 83             flag = True
 84     currP = seq[0]
 85     seq.append(currP)
 86     count1,rgv,currP,total = simulate(seq,state,isEmpty,log,count1,rgv,currP,total)
 87     return state,isEmpty,log,count1,rgv,currP,total,seq
 88  
 89 def update(state,t):
 90     for i in range(len(state)):
 91         if state[i] < t:
 92             state[i] = 0
 93         else:
 94             state[i] -= t
 95  
 96 def simulate(seq,state,isEmpty,log,count1,rgv,currP,total,fpath="log.txt"):    # 給定了一個序列模擬它的過程以及返回結果(主要用於模擬並記錄)
 97     index = 0
 98     temp = 0
 99     pro1 = {}                                                             # 第一道工序的上下料開始時間
100     pro2 = {}                                                             # 第二道工序的上下料開始時間
101     f = open(fpath,"a")
102     while index<len(seq):
103         print(isEmpty)
104         nextP = seq[index]
105         t = tm[currP][nextP]
106         total += t
107         update(state,t)
108         if Type[nextP]==0:                                                 # 如果下一個位置是第一道工作點
109             count1 += 1
110             if isEmpty[nextP]:                                             # 如果下一個位置是空的
111                 f.write("第{}個物料的工序一上料開始時間為{}\tCNC編號為{}號\n".format(count1,total,nextP+1))
112                 t = cncT[nextP]
113                 total += t
114                 update(state,t)
115                 state[nextP] = T1                                         # 更新當前的CNC狀態
116                 isEmpty[nextP] = 0                                         # 就不空閑了
117             else:                                                         # 如果沒有空閑
118                 if state[nextP] > 0:                                     # 如果還在工作就等待結束
119                     t = state[nextP]
120                     total += t
121                     update(state,t)
122                 f.write("第{}個物料的工序一下料開始時間為{}\tCNC編號為{}號\n".format(log[nextP],total,nextP+1))
123                 f.write("第{}個物料的工序一上料開始時間為{}\tCNC編號為{}號\n".format(count1,total,nextP+1))
124                 t = cncT[nextP]                                             # 完成一次上下料
125                 total += t
126                 update(state,t)
127                 state[nextP] = T1
128                 rgv = log[nextP]
129             log[nextP] = count1
130         else:                                                             # 如果下一個位置是第二道工作點
131             if isEmpty[nextP]:                                             # 如果下一個位置是空的
132                 f.write("第{}個物料的工序二上料開始時間為{}\tCNC編號為{}號\n".format(rgv,total,nextP+1))
133                 t = cncT[nextP]
134                 total += t
135                 update(state,t)
136                 state[nextP] = T2
137                 isEmpty[nextP] = 0    
138             else:                                                         # 如果沒有空閑
139                 f.write("第{}個物料的工序二下料開始時間為{}\tCNC編號為{}號\n".format(log[nextP],total,nextP+1))
140                 f.write("第{}個物料的工序二上料開始時間為{}\tCNC編號為{}號\n".format(rgv,total,nextP+1))
141                 if state[nextP] > 0:                                     # 如果還在工作就等待結束
142                     t = state[nextP]
143                     total += t
144                     update(state,t)
145                 t = cncT[nextP]+Tc
146                 total += t
147                 update(state,t)
148                 state[nextP] = T2
149             log[nextP] = rgv
150             rgv = 0
151         currP = nextP
152         temp = total 
153         index += 1    
154     f.close()
155     total += tm[currP][Type.index(0)]                                     # 最后歸到起始點
156     return count1,rgv,currP,total
157  
158 def time_calc(seq,state,isEmpty,rgv,currP,total):                         # 主要用於記錄時間
159     index = 0
160     temp = 0
161     while index<len(seq):
162         nextP = seq[index]
163         t = tm[currP][nextP]
164         total += t
165         update(state,t)
166         if Type[nextP]==0:                                                 # 如果下一個位置是第一道工作點
167             if rgv==1:                                                     # 然而載着半成品
168                 seq.pop(index)                                             # 去掉這個元素並中止當次循環進入下一個循環
169                 continue                
170             if isEmpty[nextP]:                                             # 如果下一個位置是空的
171                 t = cncT[nextP]
172                 total += t
173                 update(state,t)
174                 state[nextP] = T1                                         # 更新當前的CNC狀態
175                 isEmpty[nextP] = 0                                         # 就不空閑了
176             else:                                                         # 如果沒有空閑
177                 if state[nextP] > 0:                                     # 如果還在工作就等待結束
178                     t = state[nextP]
179                     total += t
180                     update(state,t)
181                 t = cncT[nextP]                                             # 完成一次上下料
182                 total += t
183                 update(state,t)
184                 state[nextP] = T1
185                 rgv = 1
186         else:                                                             # 如果下一個位置是第二道工作點
187             if rgv==0:                                                     # 如果是個空車
188                 seq.pop(index)                                             # 刪除當前節點
189                 continue
190             if isEmpty[nextP]:                                             # 如果下一個位置是空的
191                 t = cncT[nextP]
192                 total += t
193                 update(state,t)
194                 state[nextP] = T2
195                 isEmpty[nextP] = 0    
196             else:                                                         # 如果沒有空閑
197                 if state[nextP] > 0:                                     # 如果還在工作就等待結束
198                     t = state[nextP]
199                     total += t
200                     update(state,t)
201                 t = cncT[nextP]+Tc
202                 total += t
203                 update(state,t)
204                 state[nextP] = T2
205             rgv = 0
206         currP = nextP
207         temp = total 
208         index += 1    
209     return rgv,currP,total
210  
211 def forward1(state,isEmpty,currP):                                         # 一步最優
212     lists = []
213     if currP in A:
214         rgv = 1
215         for e1 in B:
216             lists.append([e1])
217     
218     else:
219         rgv = 0
220         for e1 in A:
221             lists.append([e1])
222     
223     minV = 28800
224     for i in range(len(lists)):
225         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1]
226         if t<minV:
227             minV = t
228             index = i
229     return lists[index][0]
230  
231 def forward4(state,isEmpty,currP):                                         # 四步最優
232     lists = []
233     """ 遍歷所有的可能性 """
234     if currP in A:                                                         # 如果當前在第二道工序CNC的位置
235         rgv = 1
236         for e1 in B:
237             for e2 in A:
238                 for e3 in B:
239                     for e4 in A:
240                         lists.append([e1,e2,e3,e4])
241     else:
242         rgv = 0
243         for e1 in A:
244             for e2 in B:
245                 for e3 in A:
246                     for e4 in B:
247                         lists.append([e1,e2,e3,e4])
248     minV = 28800
249     for i in range(len(lists)):
250         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1]
251         if t<minV:
252             minV = t
253             index = i
254     return lists[index][0]                                                 # 給定下一步的4步計算最優
255  
256 def forward5(state,isEmpty,currP):                                         # 五步最優
257     lists = []
258     """ 遍歷所有的可能性 """
259     if currP in A:                                                         # 如果當前在第二道工序CNC的位置
260         rgv = 1
261         for e1 in B:
262             for e2 in A:
263                 for e3 in B:
264                     for e4 in A:
265                         for e5 in B:
266                             lists.append([e1,e2,e3,e4,e5])
267     else:
268         rgv = 0
269         for e1 in A:
270             for e2 in B:
271                 for e3 in A:
272                     for e4 in B:
273                         for e5 in A:
274                             lists.append([e1,e2,e3,e4,e5])
275     minV = 28800
276     for i in range(len(lists)):
277         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1]
278         if t<minV:
279             minV = t
280             index = i
281     return lists[index][0]                                                 # 給定下一步的5步計算最優
282  
283 def forward6(state,isEmpty,currP):                                         # 六步最優
284     lists = []
285     """ 遍歷所有的可能性 """
286     if currP in A:                                                         # 如果當前在第二道工序CNC的位置
287         rgv = 1
288         for e1 in B:
289             for e2 in A:
290                 for e3 in B:
291                     for e4 in A:
292                         for e5 in B:
293                             for e6 in A:
294                                 lists.append([e1,e2,e3,e4,e5,e6])
295     else:
296         rgv = 0
297         for e1 in A:
298             for e2 in B:
299                 for e3 in A:
300                     for e4 in B:
301                         for e5 in A:
302                             for e6 in B:
303                                 lists.append([e1,e2,e3,e4,e5,e6])
304     minV = 28800
305     for i in range(len(lists)):
306         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1]
307         if t<minV:
308             minV = t
309             index = i
310     return lists[index][0]                                                 # 給定下一步的6步計算最優
311  
312 def forward7(state,isEmpty,currP):                                         # 七步最優
313     lists = []
314     """ 遍歷所有的可能性 """
315     if currP in A:                                                         # 如果當前在第二道工序CNC的位置
316         rgv = 1
317         for e1 in B:
318             for e2 in A:
319                 for e3 in B:
320                     for e4 in A:
321                         for e5 in B:
322                             for e6 in A:
323                                 for e7 in B:
324                                     lists.append([e1,e2,e3,e4,e5,e6,e7])
325     else:
326         rgv = 0
327         for e1 in A:
328             for e2 in B:
329                 for e3 in A:
330                     for e4 in B:
331                         for e5 in A:
332                             for e6 in B:
333                                 for e7 in A:
334                                     lists.append([e1,e2,e3,e4,e5,e6,e7])
335     minV = 28800
336     for i in range(len(lists)):
337         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1]
338         if t<minV:
339             minV = t
340             index = i
341     return lists[index][0]                                                 # 給定下一步的7步計算最優
342  
343 def forward8(state,isEmpty,currP):                                         # 八步最優
344     lists = []
345     """ 遍歷所有的可能性 """
346     if currP in A:                                                         # 如果當前在第二道工序CNC的位置
347         rgv = 1
348         for e1 in B:
349             for e2 in A:
350                 for e3 in B:
351                     for e4 in A:
352                         for e5 in B:
353                             for e6 in A:
354                                 for e7 in B:
355                                     for e8 in A:
356                                         lists.append([e1,e2,e3,e4,e5,e6,e7,e8])
357     else:
358         rgv = 0
359         for e1 in A:
360             for e2 in B:
361                 for e3 in A:
362                     for e4 in B:
363                         for e5 in A:
364                             for e6 in B:
365                                 for e7 in A:
366                                     for e8 in B:
367                                         lists.append([e1,e2,e3,e4,e5,e6,e7,e8])
368     minV = 28800
369     for i in range(len(lists)):
370         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1]
371         if t<minV:
372             minV = t
373             index = i
374     return lists[index][0]                                                 # 給定下一步的8步計算最優
375  
376 def greedy(state,isEmpty,rgv,currP,total):                                 # 貪婪算法
377     line = []
378     count = 0
379     while True:
380         #nextP = forward4(state[:],isEmpty[:],currP)        
381         nextP = forward5(state[:],isEmpty[:],currP)        
382         line.append(nextP)
383         rgv,currP,t = time_calc([nextP],state,isEmpty,rgv,currP,0)
384         total += t
385         count += 1
386         if total>=28800:
387             break
388     return line
389  
390 if __name__ == "__main__":
391     state,isEmpty,log,count1,rgv,currP,total,seq = init_first_round()
392     print(state,isEmpty,log,count1,rgv,currP,total,seq)
393     line = greedy(state[:],isEmpty[:],rgv,currP,total)
394     simulate(line,state,isEmpty,log,count1,rgv,currP,total)
395     
396     write_xlsx()

后記

這次博客有點趕,所以質量有點差,很多點沒有具體說清楚。主要最近事情比較多。本來也沒想寫這篇博客,但是覺得人還是要善始善終,雖然沒有人來閱讀,但是學習的路上還是要多做小結,另外也是萬一有需要的朋友也可以給一些參考。雖然我的水平很差勁,但是我希望能夠通過交流學習提高更多人包括我自己的水平。不喜勿噴!

---------------------
版權聲明:本文為CSDN博主「囚生CY」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/CY19980216/article/details/82893846


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM