标题: 【项目总结】2018年全国大学生数学建模大赛B题简要分析(附代码) [打印本页] 作者: 杨利霞 时间: 2019-4-12 16:18 标题: 【项目总结】2018年全国大学生数学建模大赛B题简要分析(附代码) 【项目总结】2018年全国大学生数学建模大赛B题简要分析(附代码). U9 w0 p) ]* o/ i
& T( q7 z+ T9 l# [
今天早上跟学姐室友去复旦把论文答辩做掉了,虽然整个项目基本上是我承担了主要的思路与代码部分,但是今天答辩我跟室友竟然连一句有用的话都没说出来,全场都靠学姐开场流畅地引入,临场随机应变,从而得以与答辩教授欢聚喜散。主要原因是教授竟然准确地问到了我代码里一个细节却相当致命的问题(是一个随机初始化问题,我下面代码部分会详细提到),正好学姐室友都不是特别熟悉我的随机初始化方法,我又不能当场跟他们两个解释这个随机初始化的问题。我差点当场就要以“这样随机初始化能够减少代码量”这种蹩脚的理由跟教授争辩了。好在姜还是老的辣,辩论队队长出身的学姐一顿 Speech Art 操作成功忽悠掉了两位教授,最终两位答辩教授还是认可了我们的模拟仿真方法[捂脸]。事后细想以后我成功也好,失败也罢,恐怕也是成也言语,败也言语。也许我确实能够成为一个有能力的人,但是说话艺术确实是一门很大的学问。不过看我运气一直这么差,大概率还是凡人一个落入俗套吧[摊手]。 9 k+ f: B. g/ p; L0 c- x7 O f# I6 K6 J& W
言归正传,本文主要介绍我们小组解决2018年全国大学生B题的思路分析,不代表标准答案。当然我还是有自知之明,本身水平不是很高,再加上三天时间限制,自己做出来的模型以及算法肯定是比较差的。这里仅仅从我个人的思考角度出发写一些参考思路作为分享讨论,希望各位读者朋友轻喷。 I0 R3 i! n4 Y' A/ L ' c' K5 A2 u9 I. a- S4 v m问题分析. d9 ]& l& E. L# R2 V& k$ a9 \
8 ^+ Q4 m B# X2 X今年的B题确实与往年有很大的不同。往年的数学建模问题往往具有比较好的开放性,问题解决存在较大的建模空间。今年的B题的题干本身就几乎是一个明确的模型(8台CNC+1台RGV+CNC定址),加上第二道任务要求我们根据给定三组数据完成八小时内的RGV详细调度方案,并写入四张Excel表格,给人的感觉就是要求我们去完成一道填空题,然后附带写一篇论文[尴尬]。* r2 t/ j* u2 b7 h3 K' y2 C
5 d/ s( w: |" ]& u4 M为了方便各位读者对赛题的阅读,这里给出链接:https://download.csdn.net/download/cy19980216/10708725 $ y+ `/ E) H2 a, @, v6 f7 o7 D: B) b 5 P( b; Q# k/ Z6 j) u问题一共有四种不同的情况:一道工序无故障,一道工序有故障,两道工序无故障,两道工序有故障。, ~; A, L* F, a& n
: f# l: L3 q6 Z+ @1 v一道工序无故障$ m% o4 j) x- m/ B5 l
% Y, T; J( I$ ]2 _第一种情况是最简单的,直观上直接不停地1234567812345678……按顺序上料差不多就是最优了。但严谨地来说,虽然题目中给的三组数据确实都是用这种最幼稚的策略能够达到最优,但是如果对于一般的情况而言,比如最极端的情况下,RGV移动时间无穷大,那RGV显然就只会不停地在121212121212……这样原地上下料了。- M- ~# [- Y: L. F
4 T7 a: N& J" T& n4 n! _4 J. m
然而我们发现无论参数怎么变化,最终RGV给CNC上下料的过程始终是一个周期性过程。当然这个似乎很“显然”的事实却是相当难以通过数学严格证明的(参数已知的情况下一般比较容易证明,但是所有的参数都是未知的情况下是很难严格说明的)。我赛后也仔细的思考过,但是也没有得出很漂亮的证明。我最终仅仅是针对给定的三组数据使用了遗传算法对RGV前17次上下料(17次是考虑从初始状态开始循环两圈的最短路径)的最优路径进行了搜索,并且利用穷举证明了这是前17步最优的上下料次序。之后基本上就是不断地循环。 2 }+ V, `- h1 g6 C+ V % u/ ~/ r3 N0 N+ K( @0 G1 |: [这里的模拟退火遗传算法比较鸡肋,所以我不详细说明,在第三种情况我会详细说明模拟退火遗传算法的原理。) Q: r$ i! B8 Y! S4 @
* b( F1 A2 _ B: q8 N9 c; k* k0 b- g以下给出第一种情况的模拟退火遗传算法算法以及对应的穷举最优证明 ↓↓↓/ i- Q9 V5 b7 \7 B& l
# -*- coding:UTF-8 -*- ) Y& |& c6 G, @! g: B. I"""+ [2 N/ `6 _: U! R: X. I @
作者:囚生CY N5 I( V1 z4 ?/ R2 v( f3 [/ w8 ` 平台:CSDN) [& l% s, D! g/ Q$ k
时间:2018/10/091 g# u" n! j8 z% V5 z
转载请注明原作者2 ^3 P- i3 A [: R
创作不易,仅供分享 . Y8 i+ u9 q _ `' s"""( e q5 h' C: y( H6 ^; l& P
1 F. w( c! A" o. Ximport math ! N/ ?0 l) ?. |8 Wimport random1 k2 O3 K d' q& _* O9 ]
import itertools ) Z; x" I2 M* |7 \# L 0 J. I* k' @) H) T* ?""" 选取一组数据 """ : `) M, r; Z5 T E2 W& lT = 580 , [4 l2 B: x1 J7 q: k0 }/ pd1 = 23# O1 \, D" L# ?% o* K9 f8 x$ g8 f
d2 = 41 2 R2 k0 p' t9 Q, m' |d3 = 59. M B9 y/ E# O O H! K
Te = 35 ) L! O* A6 l7 q. i. f# }To = 30 # {6 m0 |; ]$ t! ~Tc = 30* A6 {( I: e# ?9 q4 M) k* V, o
& f: G3 H& c3 f0 P" P7 Y0 r0 G5 kCNCT = [To,Te,To,Te,To,Te,To,Te] # CNC上下料时间 9 R- Z `5 R7 u$ |7 B3 H1 d6 L# ?: W# i9 p6 r
N = 508 ~, d+ ?& P. g% ]5 m# U2 b
L = 17 : e$ f% g* _' R! y 8 ^3 [% o: ?# ?9 ZvarP = 0.1 3 b/ {: }# v/ A/ M% _% ` O& n" Y/ RcroP = 0.60 T% c* R! i$ Z1 S2 X7 b: Z
" u5 z* a) U2 N) ScroL = 4 / a5 u. h. |4 p& V: Oe = 0.991 I6 w3 {, Q% l5 \6 ~
! X1 G5 @0 C" d9 @, h* f
tm = [ 5 @; s' [8 z# n( ?- {5 P [0,0,d1,d1,d2,d2,d3,d3],) Q4 F; n" `9 B7 n5 A( `0 m* U
[0,0,d1,d1,d2,d2,d3,d3], 8 T# O3 |/ F+ }/ t4 V [d1,d1,0,0,d1,d1,d2,d2],0 a& P4 q9 l/ l' ^# x8 l/ |
[d1,d1,0,0,d1,d1,d2,d2], & L& c/ j: L, k" p* _$ R1 O5 J' B, z1 y [d2,d2,d1,d1,0,0,d1,d1], , v0 n2 P: H3 t8 o2 U6 Q. W3 ^6 c) E+ i/ I [d2,d2,d1,d1,0,0,d1,d1],4 E3 D# Q, V/ s, i% O
[d3,d3,d2,d2,d1,d1,0,0],: ]$ M1 |% U9 }% p
[d3,d3,d2,d2,d1,d1,0,0],! H7 y7 {& J, G( d2 @3 J
] 1 {4 G; Q4 [4 z/ a 7 }# o) J8 k) W' [4 q# X; M6 `def update_state(state,t): . }( [- p: }2 h0 d& T2 p length = len(state) ) l t) v- B; @& w1 ` for i in range(length): ; z3 Z' {( Q3 r; q% Y$ C" E% s# ? if state < t:! ?3 f7 C, B# n- a: J
state = 0 7 v% G! c# ~) T1 J else:9 }5 q& E3 S8 N9 z8 F; S
state -= t $ {# v- u l. z) p: ? return state - u: l6 R+ S; z# O% D 5 [" G% A& P. S/ u$ `2 P3 {& E3 ydef time_calc(seq): 6 S* Z/ S0 }6 p; C* A: [7 X state = [0 for i in range(8)] # 记录CNC状态 7 ?# D* y9 {4 K. Q isEmpty = [1 for i in range(8)] # CNC是否为空? ; C1 M8 J& r0 ?* c- Q% j currP = 0 # A* ^2 h2 k! ^. e+ w } total = 0 ! f9 h# H8 w1 }0 u; V ] length = len(seq) % p6 V) z* |% Y3 z" K for No in seq: # ~* D7 P0 s& T) y$ y nextP = No * e. W* T5 S# f' m t = tm[currP][nextP] , `5 @" f# F: f1 t, L total += t # rgv移动 0 @) s! ^9 c0 J- {4 S9 S7 x state = update_state(state,t) # 更新state5 T) I$ v e, C4 V6 R3 g! k
if state[No]==0: # 表明CNC等待0 m* ~" P& ~0 _2 |
if isEmpty[No]: # 当前CNC空 6 w4 S7 i! p. v$ n+ e/ k t = CNCT[No] W3 f1 v0 n9 k; V, w5 } isEmpty[No] = 07 }6 C. Q- j' L( {" K, B
else: - v+ I+ \$ S9 ^' Z t = CNCT[No]+Tc( d' a6 p% P! O0 L! W
total += t# e$ R# \, q# a: h& G
state = update_state(state,t)5 L1 j! R6 d+ {7 |6 F$ D0 f
state[No] = T 4 n7 b: d5 T' j4 m$ r else: # 当前CNC忙* t8 V, k/ E d7 {! k
total += state[No] # 先等当前CNC结束 ! ~; m% `* m" F1 i) R state = update_state(state,state[No]) 3 Y) V9 r" y6 v' E/ A0 W' ]
t = CNCT[No]+Tc , E" P, ^0 X- v: |8 T, b total += t 1 P" ?$ L" W8 v/ ?% n state = update_state(state,t)+ s- ~: W/ g8 _) \: N$ S
state[No] = T ?0 o- A- \' r7 f: R6 z* Y6 l
currP = No |' ?& ~) z+ p total += tm[currP][0]3 t- I( F" G4 u$ b# a
return total 2 A* |7 I% G# L. @( L# j- n! Q$ {. J- T
def init_prob(sample):6 c' v+ i- U8 @$ s$ i7 V
prob = []& B1 @+ g4 k8 |4 d- X
for seq in sample:! P, s- `5 l( T2 Z( [0 T3 u" o
prob.append(time_calc(seq)) 5 s/ |. a }" U; |4 d; e8 I maxi = max(prob) ( ?1 M8 B+ k" \6 B8 } prob = [maxi-prob+1 for i in range(N)]( ?) Q w# S: @( q( j3 g: r
temp = 0 " w$ v1 T( c) y9 W$ T for p in prob: w$ ^& H. Z. [7 B6 h) B+ A+ F temp += p# F/ j! W& A) d6 K1 y$ A
prob = [prob/temp for i in range(N)] 6 r1 a% ~/ z" _: P# f3 B for i in range(1,len(prob)): , @% i8 r8 I3 O# l7 a3 }) d$ b prob += prob[i-1]0 x3 p) D. Z! Q# v- n$ Z* z8 z
prob[-1] = 1 # 精度有时候很出问题 6 U" Q- ~# ?) w3 B. T0 Y0 Y return prob/ I$ Q" o0 |8 Y# b/ @7 m/ t
9 S; y r2 l% R" xdef minT_calc(sample): ) O" M- `4 O, V5 i0 C) c% z minT = time_calc(sample[0])" s8 ]. O7 f; v8 [
index = 0' K: c- S3 |% V0 X/ Y0 D
for i in range(1,len(sample)): , \/ Q- U; z# j$ a. o$ e t = time_calc(sample) a. K2 { c" C: a( M# @- n6 c if t < minT: $ Y; ?7 m+ u6 { index = i# j# A9 ^4 z( Q2 ]; N
minT = t + L( _" H& ?' X' ~ return minT,index: Z1 W# \! ?5 K& o
) _, L8 X$ a# G6 [: n- K
def init():- Z1 }) z9 b! F; y: G& b/ A
sample = []- i2 C$ @1 N1 F0 T9 H9 C4 A: P
for i in range(N):; n% e2 _5 v; m1 g& E5 S, H4 O0 H2 z4 c
sample.append([]) $ [% P1 X9 ?% z9 U- h, d for j in range(L): 0 F! v' r4 ?6 G3 w- [ sample[-1].append(random.randint(0,7))" S7 w$ [. k, Q; [) [- {
return sample 2 p* k! m5 Q, O" T2 ~; a . c2 a t+ r) D q6 y. Y% c0 s, _def select(sample,prob): # 选择9 s" s& |# p* `( ^) D' `
sampleEX = []# V- c+ ^, G. P$ j; y. r6 L# I! E
for i in range(N): # 取出N个样本3 d( B- W i( I, a0 J2 X" T
rand = random.random() # h* g- P* _+ S. N2 m* x for j in range(len(prob)): 5 J- w; t6 `+ x# [# ? if rand<=prob[j]: + {& v+ m, ]! Z7 G! M) M sampleEX.append(sample[j])9 A) P/ l: e- r a
break $ u7 n# s8 T, n3 Q! v4 r0 d g return sampleEX 9 k0 b2 u1 |7 L* N" Y1 `; {8 F$ e, s- g! d3 y: _
def cross(sample,i): # 交叉0 I: q1 p) t! S7 O$ F! S/ ?
for i in range(len(sample)-1): 4 A# _+ `" n; n/ A S: R8 [ for j in range(i,len(sample)):- x" I$ [ U' p( g) @% k/ @% ^
rand = random.random() # ^% K Q- m) `# M: ~. a7 B! D/ n if rand<=croP*(e**i): # 执行交叉) M" I$ c4 r" ~' @- G- x6 Q5 |8 D
loc = random.randint(0,L-croL-1) 9 B3 d" `- L) m) E: O7 n0 } temp1 = sample[loc:loc+croL]5 l2 S7 ]2 L, S
temp2 = sample[j][loc:loc+croL] w1 N. g4 I- Q+ i7 f7 m5 A- [8 V
for k in range(loc,loc+croL): 4 u# j+ ~7 Q9 C sample[k] = temp2[k-loc]+ {8 n: B' m& Q2 g+ P% M$ ^
sample[j][k] = temp1[k-loc]' M8 g/ m J: i* M$ I' _
return sample . y; a: @+ q& _/ u1 L( ^$ h* a . y/ P8 H4 w; {* g1 D" U
def variance(sample,i): # 变异算子 - N+ O% Q& L/ x' T5 b, A0 ^
for i in range(len(sample)): / G1 o ?" [! _ rand = random.random() 0 x- }8 ?! f D# N1 J9 i% @ if rand<varP*(e**i):' ]0 p" g- Q0 b8 Q. a
rand1 = random.randint(0,L-1) . y- U& q5 U- K" v# V5 D rand2 = random.randint(0,L-1)+ O) G8 B3 ]7 O, I% U; N
temp = sample[rand1] 0 l* e6 F+ `, ] sample[rand1] = sample[rand2] ; h0 F: P- k V" p9 p0 t+ }. R/ }+ N sample[rand2] = temp: R. }& ?6 G& d F' R6 l
return sample / I4 P, e3 D" Q7 `5 Z( t & z% h# ?+ G) ~def main():) V |* W: I% K0 ~
sample = init() 9 A# }" f" j" ? mini,index = minT_calc(sample)4 b: ?( D* d2 _! {
best = sample[index][:]8 C9 k& P4 ]5 |1 Z& h
print(best)6 a+ T7 d; ?6 G! c" h8 U9 E8 o
for i in range(10000): / z" C# m) O9 D1 r5 F print(i,'\t',minT_calc(sample),end="\t") 8 |; l" `0 Z0 E" v% L" K prob = init_prob(sample) . ^) m/ M/ n" J2 h" g$ B' t/ f sample = select(sample,prob)2 w7 I5 h9 j8 t6 g5 p; a
sample = cross(sample,i)6 i& Y4 m- Z( {6 i( d! [
sample = variance(sample,i)/ N/ E! M& a# a0 V0 ^* n5 }
mi,index = minT_calc(sample) ! b# B n4 r- G8 O& g if mi>mini and random.random()<e**i: # 精英保留策略" U+ Q. N. { |2 T9 y% J9 {
rand = random.randint(0,N-1)9 |0 L2 v) f" C! K( K9 a: T! X& C
sample[rand] = best[:] 9 @8 u6 _2 E* h! p' V9 G$ b4 ?$ P' A mini,index = minT_calc(sample) 5 E1 o: g* P* r ]/ w- n, I( t% n best = sample[index][:]+ H6 E) ]) V; ~0 V4 v3 ]9 F
print(best) : q9 X9 h; C( `0 S print(sample)" @- o8 v. `( D9 n, {1 ?' R
* e0 Y3 A0 f8 `, D6 r [
if __name__ == "__main__":7 {3 O! o: i$ X" Y) T7 j
main1() & }1 m: L, \/ v7 Z """ 穷举搜索验证 """ , q0 Z! _& M1 Y/ ?; S, U a = list(itertools.permutations([1,2,3,4,5,6,7],7))% ?. E, y% R, I
ts = [] # f8 j' P3 y7 J1 w2 T) L6 u first = [0,1,2,3,4,5,6,7,0]. E/ M' B0 V9 T
for i in a:. r2 g5 ? Z" p" Z3 U5 D
temp = first+list(i) 1 H8 T6 `6 E+ R" n% s& N temp.append(0) A" ?# ~- `( P
t = time_calc(temp) 6 ] }; k9 y7 e, k' K- W* O# e ts.append(t) 6 B5 y5 {; E r% _% R+ m8 [2 H% }4 V print(min(ts)) ) D8 U* H- t- S, K4 I
print(time_calc([0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0]))1 E1 K/ c j; q. w1 I% T
8 I7 h$ {/ K6 u i
" i" m! B/ m0 I; [4 [9 U1 m
一道工序有故障 # ^( I; i5 L+ w, p) j: {; V+ m8 u. @8 i& v9 ]8 Q1 G# _
这部分是学姐做的,学姐用了偏数学的思考方式,仍然从循环的角度去考虑,主要考虑故障发生是否会影响当前循环,是否需要建立新的循环。因此就没有写代码处理问题了。具体的思路我确实不是很能讲清楚。但是这里面有一个非常大的问题,就是如果出现多台CNC同时发生故障怎么办。关于多台机器同时发生故障的概率,我们通过估算认为以给定的三组数据8小时内会出现这种特殊情况的可能性大约为30%。这个问题是我无法很好严格处理的(当然如果用贪心算法也就没这么多事了)。 2 u8 I, ]4 I( N8 f8 T$ F$ w/ D + f1 K8 i6 P; Z9 H- Z6 o两道工序无故障 & 两道工序有故障" t6 X- [9 x, f' Q$ L2 M" x% ^
, C7 g2 ^% m. K# G+ i0 X这两个部分都是我来处理的,因为使用的方法大致相同,就并在一起说了。 1 G7 i. Z# f# x2 @2 n8 c% R( I- ^ ( X! A; W* ?; B' f' w0 G两道工序与一道工序最大的区别在于三点:' e/ S8 v0 M4 a5 w7 H6 T
8 {7 j) {2 ?; ?& V$ H9 d1 z. z1、开始要处理CNC任务分配:分配给第一道工序几台CNC,分配给第二道工序几台CNC?具体怎么布局?+ e6 S- m$ R2 [1 L ^* ?
: v8 t. t H, _4 k5 x 9 L7 f7 _% ^' a, Y I; Y2 M# 第3组# d2 O3 X7 u( ^/ g# R- k4 y
- C& |' X- J2 x8 I
""" " X& u* m. h% t2 x6 V" ?; Pd1 = 18" @8 P3 e% v7 K# D& f% M
d2 = 32, Z N* U8 ]+ g; ]" k, |9 H0 f- z
d3 = 46 5 C8 D' q4 q8 e2 ~T1 = 455 `4 G2 j( y j9 [7 c$ [T2 = 182 $ p* C% W2 I! q' V5 LTo = 27 " d8 B9 A) T# G# g0 fTe = 32 ; j S( K; {% {' y+ H- h9 e# _Tc = 25/ o4 w$ a9 J0 b# ?2 D2 a
"""/ J! \: Z. w! F8 K2 ]
0 s6 ]5 W0 `( [9 ucncT = [To,Te,To,Te,To,Te,To,Te]8 c' Y2 [ V% W9 j+ E# b
tm = [7 B7 p0 I! s8 R3 Q3 C
[0,0,d1,d1,d2,d2,d3,d3], ( w! l ?3 T7 X' r3 Y( v [0,0,d1,d1,d2,d2,d3,d3],* g5 P0 J7 Q; K- w
[d1,d1,0,0,d1,d1,d2,d2], _# h/ q+ @% C0 X }( x [d1,d1,0,0,d1,d1,d2,d2], # W( t6 f( ?% `+ L! N' t( K [d2,d2,d1,d1,0,0,d1,d1], 1 t. ]; [% U( z4 S [d2,d2,d1,d1,0,0,d1,d1], / A( `3 I" s- O' M2 j$ V* @ [d3,d3,d2,d2,d1,d1,0,0], , M* E: }1 U7 P [d3,d3,d2,d2,d1,d1,0,0], R2 s# R# c4 P] ' y2 s/ G, t ~4 q9 r- yType = [0,1,0,1,1,1,0,1] # CNC刀具分类 ' T0 ]: D1 X l$ @$ x4 ^ 6 e& N1 G! j u7 K- V$ \2 ~4 P0 _A = [] # 储存第一道工序的CNC编号9 s _5 d/ u$ d8 n7 y
B = [] # 储存第二道工序的CNC编号 ' K, g/ V1 ~5 c; ?* ofor i in range(len(Type)): : o; ` `3 H$ D, q* L9 B; [& I if Type: 1 Z- J1 j7 g$ j; h+ M B.append(i) 4 y2 J1 [7 M; u6 u0 L, [ else:. k; T: t% L, m& ~9 T: X& q
A.append(i)9 X7 Y& q6 X/ @9 [3 a0 ~3 j
: K$ d8 V, h- {% M" c; V/ _( ], ]
def init_first_round(): # 第一圈初始化(默认把所有第一道CNC按顺序加满再回到当前位置全部加满)3 e3 _* \( `2 v
state = [0 for i in range(8)] # 记录CNC状态(还剩多少秒结束,0表示空闲)" k8 \( S' K: Y; _5 w$ o. h# F
isEmpty = [1 for i in range(8)] # CNC是否为空 : ~! `! s: k$ G3 d log = [0 for i in range(8)] # 记录每台CNC正在加工第几件物料5 g7 X& V. F& ~: b! r
count1 = 0; `3 P1 T+ o% T$ D A
rgv = 0 # rgv状态(0表示空车,1表示载着半成品) 1 m0 i' y$ _ f( O" Z( L currP = 08 i4 T- y2 ~" _- @) E- {
total = 08 v/ o! Z l, c6 w' }0 \
seq = [] $ ^- E% [& A# a! ?( ?& k+ P/ E flag = False, ?8 {8 d" ~. ]- h
for i in range(len(Type)):! I/ s0 y+ V( J2 `
if Type==0:+ r2 j* I' a% t* T0 R
seq.append(i)* C2 D: T. k+ P5 i. A6 R0 B
flag = True 9 R. E! {4 D1 L" H% a: R currP = seq[0] # K8 Y9 o* c! q+ A seq.append(currP) ; }0 h0 l' U# I( o9 R/ P count1,rgv,currP,total = simulate(seq,state,isEmpty,log,count1,rgv,currP,total)* l# R) F6 J/ S) y
return state,isEmpty,log,count1,rgv,currP,total,seq 5 ^. F ?9 D% U* a0 @* ?& n! w. ^) i& ?
def update(state,t):: j7 ]9 X; @9 ~
for i in range(len(state)): ; A. ^( e3 \/ i" k& m6 [ if state < t:# Z/ f) o1 H& M' `. r4 Y/ j7 j) h
state = 0; T T0 V5 U6 Y+ {. P
else: # A. V5 y$ Y; u Q6 f state -= t( ^9 v' G; P: @$ b
, l3 Y9 {; b! u; e
def simulate(seq,state,isEmpty,log,count1,rgv,currP,total,fpath="log.txt"): # 给定了一个序列模拟它的过程以及返回结果(主要用于模拟并记录)' d, ~4 [. F# r, a, O1 c6 l6 m
index = 0: u0 ]( X& X2 G% C R) E
temp = 07 L; ^! ^8 w; S4 A2 E1 J: `
pro1 = {} # 第一道工序的上下料开始时间9 P, C" ]# p! J# ~- T; w8 G
pro2 = {} # 第二道工序的上下料开始时间 - ~5 f) t' z, d# ?" Q f = open(fpath,"a") Q+ Z4 X" \- A5 v while index<len(seq): - A. ]3 r, \* C+ h' u print(isEmpty) : ]- C9 m" V1 S) ?3 `2 {( i9 ] nextP = seq[index]4 v1 a; b s$ _$ h, R% ?: R8 Y- c# L
t = tm[currP][nextP]3 H. {6 i2 F1 G8 C1 p
total += t 5 D9 B- P+ }/ _! H( l7 b7 l" Y% l# ] update(state,t) , _9 Z0 O8 ~7 K" b$ Y if Type[nextP]==0: # 如果下一个位置是第一道工作点6 E* a6 Y0 E$ _/ t {
count1 += 1 & z# h, m1 b5 `5 X+ ` if isEmpty[nextP]: # 如果下一个位置是空的 2 L2 ]' L* R! P& D5 |$ H f.write("第{}个物料的工序一上料开始时间为{}\tCNC编号为{}号\n".format(count1,total,nextP+1)) , c! C6 c8 [: L* z4 u* U/ N) c$ d5 V0 ? t = cncT[nextP]0 \3 e0 k% h8 T* }1 N
total += t ! }, c2 n7 b8 W+ R update(state,t)! F* p0 [6 r7 m0 Y, i& N) y9 @
state[nextP] = T1 # 更新当前的CNC状态 4 J2 f7 O! g* Q isEmpty[nextP] = 0 # 就不空闲了6 d( p5 u) d; J( L' @& c
else: # 如果没有空闲7 h9 q0 K( Z; b' i
if state[nextP] > 0: # 如果还在工作就等待结束 / N4 C$ ^) i5 ` t = state[nextP] H' m; X2 C1 d z' A+ Z
total += t 9 r7 g: q+ U3 U h2 T6 G) x update(state,t) 8 t6 x% T% Z& s% N8 b f.write("第{}个物料的工序一下料开始时间为{}\tCNC编号为{}号\n".format(log[nextP],total,nextP+1)): p1 L4 d$ m$ Y) j4 E w8 M( g2 a
f.write("第{}个物料的工序一上料开始时间为{}\tCNC编号为{}号\n".format(count1,total,nextP+1)) 4 D# @" b2 M, C+ e, w) Q. f t = cncT[nextP] # 完成一次上下料 A1 M+ \( q: x4 v+ i2 B. b
total += t ) v7 Z( g; e" J update(state,t)+ v+ Y" g4 R( U7 o1 F( v) i# d
state[nextP] = T1/ o9 @. W2 x* t" @8 Y: A: _2 X
rgv = log[nextP] % Q$ I. ?# k5 r/ P4 _( }# ^1 t& B8 A log[nextP] = count12 t. v. g$ V* U2 M' j' \
else: # 如果下一个位置是第二道工作点 A0 W5 C& G4 ~* N$ f, \. Q
if isEmpty[nextP]: # 如果下一个位置是空的 3 F- [2 w/ P. D* [ f.write("第{}个物料的工序二上料开始时间为{}\tCNC编号为{}号\n".format(rgv,total,nextP+1)) 9 U; d- |; e7 R t = cncT[nextP]" R: z6 c/ i5 {) c$ P) D2 x
total += t - |4 k8 R* }5 n1 M5 f update(state,t) & o6 \& K" M; q$ s) e state[nextP] = T2" R2 x) a+ N* Z- X; ?0 Y. p$ x" c
isEmpty[nextP] = 0 ) r- W8 n) w4 P9 v% U0 N
else: # 如果没有空闲 , T- `. \6 a9 v+ o f.write("第{}个物料的工序二下料开始时间为{}\tCNC编号为{}号\n".format(log[nextP],total,nextP+1))& e# r n% s$ \2 h
f.write("第{}个物料的工序二上料开始时间为{}\tCNC编号为{}号\n".format(rgv,total,nextP+1)); O1 y0 D0 K5 L7 e4 e
if state[nextP] > 0: # 如果还在工作就等待结束3 y1 ]& @' O4 j
t = state[nextP]% ?- \$ V. \! m$ B9 U
total += t( [$ m4 J: J9 p' `/ G
update(state,t): F C" f, R: `" `
t = cncT[nextP]+Tc $ r J. b7 d) p total += t 4 a) g# g1 ~ b O update(state,t)% k D: X X+ Q) S$ |
state[nextP] = T2) W3 D$ z( x" Z
log[nextP] = rgv / J4 p7 L" E4 O1 P* ~' P7 j rgv = 0 & @0 \$ U9 j) q. r B+ X currP = nextP$ g+ L' z' @) G G8 k
temp = total 4 M1 N6 C% ~* ]# `+ V! D index += 1 / y0 R9 v7 V9 _) Q8 ~! A: C f.close(). z: j7 W9 k) p
total += tm[currP][Type.index(0)] # 最后归到起始点" a1 |6 [/ e; W9 k7 Q
return count1,rgv,currP,total a9 m; f# r/ q" V * C9 D% D0 C3 Z2 W% Mdef time_calc(seq,state,isEmpty,rgv,currP,total): # 主要用于记录时间& R6 F" z- X8 P s
index = 0# Y3 Z6 Y) ?" Y: A
temp = 0 1 c% O1 y, j# E; M5 Y while index<len(seq):" h& c n) j! w( a
nextP = seq[index] $ F$ W8 j2 u6 Z) m6 @+ L: | t = tm[currP][nextP] ! r8 m: k0 ^. b/ m4 |) a% N! l total += t) M$ T$ k! n0 j6 A
update(state,t)( [/ _( p5 c1 K$ O i
if Type[nextP]==0: # 如果下一个位置是第一道工作点) P0 C6 v3 Y9 S0 }9 g" ^% v
if rgv==1: # 然而载着半成品 + g q, f: m% N# H seq.pop(index) # 去掉这个元素并中止当次循环进入下一个循环- g4 j+ e: G) N+ ?* ?
continue . M9 S# t! r& t' f9 J
if isEmpty[nextP]: # 如果下一个位置是空的 ; G/ S3 h8 C$ Q2 ~/ u t = cncT[nextP]: Z/ h! @% _ z' X! B7 l
total += t( j: `# {0 }5 D% L6 ~" }! O8 K0 v
update(state,t) `! {' J0 ~' }( V' ^, D state[nextP] = T1 # 更新当前的CNC状态7 G% q6 e# M/ [' |, x: Q
isEmpty[nextP] = 0 # 就不空闲了+ R9 o! X ?8 N* I
else: # 如果没有空闲 | G$ Z8 [& S3 d" v
if state[nextP] > 0: # 如果还在工作就等待结束 + \. W$ s' u5 d* @& b t = state[nextP]- B7 {( d! n: G6 e6 T
total += t: u* z: l: ?/ w: ]* P: p
update(state,t): I$ Y- ^% v o& k
t = cncT[nextP] # 完成一次上下料8 I' I/ \. Z8 Q0 ~3 [$ r. t
total += t 5 u4 ]: B% U( v' n% t update(state,t)1 V' S1 n9 y; E! ~ U# v
state[nextP] = T1 & ~7 w( s8 }! M0 w" C9 Z rgv = 11 p- ]/ o4 @( Z9 q
else: # 如果下一个位置是第二道工作点 6 q2 }4 m3 K' I& v' s2 k if rgv==0: # 如果是个空车 ; F/ O; o8 o2 I/ D2 m, n& }! ~ seq.pop(index) # 删除当前节点! B8 ^( n" m' F+ {5 s4 ^
continue. q: F; v% O4 d* r
if isEmpty[nextP]: # 如果下一个位置是空的/ A1 c( T( Q1 Z. }
t = cncT[nextP]" C+ _$ N5 S7 H8 D$ l! n2 l' Y2 c
total += t0 c! e. J- `+ P- B
update(state,t) J; B1 Y" H! a* h
state[nextP] = T2& _& D- y0 U8 s% `( k
isEmpty[nextP] = 0 / R; e& M$ m; h. y3 r6 m else: # 如果没有空闲 w8 k2 H; Y, m3 C' c5 I) q# T if state[nextP] > 0: # 如果还在工作就等待结束# r0 y; B- B; V0 q. B* h. b
t = state[nextP] / B( U5 [9 B! M# ~0 m6 [% S& ?$ m" l total += t 9 B# [7 Y3 Q4 X/ k$ ~$ G' B update(state,t), `/ i# q7 B8 A7 ?9 s6 y7 B" ^
t = cncT[nextP]+Tc ; f$ a" v- Z& V3 H& H6 }8 n- L6 q4 e total += t$ p' T. f" r' Q8 z: I
update(state,t)3 T% o9 m( l! N% f% K6 W' Q
state[nextP] = T2! O5 W/ O3 S' k# H
rgv = 0 ! x# b/ W. b; A' C0 [3 {2 u currP = nextP 3 B) h9 x# f4 M m* e& F0 [ temp = total , w7 [' S. Q a
index += 1 # U' Y/ o; {& \
return rgv,currP,total! R- k L D7 V d5 b: [
; r) W" H* p+ T$ ~, ~9 f# Q2 q4 b+ ?def forward1(state,isEmpty,currP): # 一步最优+ k0 X: e0 b0 m! U |
lists = [] , F# Z3 h; D( F- u! O; f: ?( H if currP in A:" `" R |# U$ y) A2 T, z4 l
rgv = 1& I/ w* u( P' z8 A2 I& o$ O5 ~! G
for e1 in B:' V0 |. q8 ~: V- r/ I" _
lists.append([e1]) , X8 o) B3 Q5 ^4 | B" q5 n: E ) E1 Z) T0 y* Z9 G
else:, X" e& c' \4 ]4 K7 Y
rgv = 0 0 G- H; w. U* Z" o" K7 _% H for e1 in A: C- U \) w+ @% D% g/ L0 k lists.append([e1])" @! A, i5 [! H4 C6 _9 q# J5 g
# H, p2 H" A5 q, b' Q1 T' ~( S minV = 28800% G8 Q) _! j# U8 a
for i in range(len(lists)): # n! c! i/ O' s- Z9 F t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]. a5 ^; Y) C' T/ z% i+ B. N
if t<minV:. W, M$ b2 H' _
minV = t / A3 w+ Z) K" m3 k5 s8 E index = i % G" } p2 R! \0 h. S return lists[index][0]1 W; b7 Z) k' W1 b, \ H
8 x6 Q+ f! e& j3 Z/ R3 S
def forward4(state,isEmpty,currP): # 四步最优' P$ c8 j9 I) m* D {1 F
lists = [] 2 j1 I' n4 B8 Q0 B4 i1 L$ ]1 F """ 遍历所有的可能性 """0 Z. b2 t* Q6 \$ f, Q
if currP in A: # 如果当前在第二道工序CNC的位置& F! i* e* ^- r; C
rgv = 1 ' I( Q8 _. M; L# U" C0 J% E for e1 in B:- p, v( j0 i B9 s( F
for e2 in A:. C! o' y2 H! s$ X. |8 E& f4 ^1 K- R
for e3 in B:" \* T( C1 b1 `* O+ l( l$ Z& S
for e4 in A:8 V1 O& Z2 o" J5 y
lists.append([e1,e2,e3,e4]) ; c) ?& u, c3 u9 e `4 p else: ! _" V) D9 ?2 D$ |% g rgv = 0 6 T1 Z$ ]+ p% |+ c1 m2 N' Z ? for e1 in A: ' O5 ?, o2 x7 M b for e2 in B:2 r/ c; D. q! i* B2 u+ J
for e3 in A:' d$ ^2 W3 i7 Y
for e4 in B:& E- A% g+ X3 w
lists.append([e1,e2,e3,e4])) @) O3 L! ~0 ~: }( Z. A4 S
minV = 28800 5 p' H) X! X& ] for i in range(len(lists)): + i8 L! x" m' p t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]3 p: a: U* }2 ?+ C9 Y7 O. L4 J4 ~
if t<minV: ( [: p% ?# G. M* x0 s7 r# s minV = t( ~$ {2 f( r, q* T2 n% ~3 d
index = i2 N3 d7 V& Q+ k" M3 d
return lists[index][0] # 给定下一步的4步计算最优 ( s* Z$ v: k6 Q( a. D# Q8 A2 Q 3 r' r4 y: H: \% N0 ^' d: Sdef forward5(state,isEmpty,currP): # 五步最优 : z. x+ I4 m' _ lists = [] 8 Q0 B% L2 g- c. W* D# y """ 遍历所有的可能性 """5 m. f ?. m4 x' x
if currP in A: # 如果当前在第二道工序CNC的位置 9 C w; a- F2 \/ p rgv = 1 ' b: v2 f: I d1 F% M! f) C for e1 in B: ) V7 S6 n: O; n; t: R for e2 in A: 7 I4 v* v" v' y: b, [" g4 g1 ?: k6 _ for e3 in B: O' B' M; n1 S( D- e0 }( L" ^ for e4 in A:# Y& W0 p p+ ^+ q, l
for e5 in B:* a" y6 k9 d( \; Y
lists.append([e1,e2,e3,e4,e5])0 l8 k8 g9 A, o
else:& k1 ~# g" ]5 T& d
rgv = 0 ( a- g6 Y& t- ^ for e1 in A:$ K& u7 N5 K% D! k1 O
for e2 in B: " @* @$ v4 }/ J C( T u! D for e3 in A: + z9 W; b: ?" I: [ for e4 in B: 5 m% {! f" M s: g; C for e5 in A:' x+ _% R u A
lists.append([e1,e2,e3,e4,e5]) 7 B4 D. s* W, j! A0 Y* n minV = 288000 t8 `; B( A; _" X; e% V$ \
for i in range(len(lists)):) X! g: q) w- ~3 ?- G
t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]+ I* }8 v- B5 w
if t<minV:! l0 _8 W" R. Y: O, K4 k/ V
minV = t # h( p9 p# }. s index = i 4 h* c$ A% r7 |$ g" l return lists[index][0] # 给定下一步的5步计算最优 / L" F1 d* E) G* ]1 h0 @ : c2 q9 g/ R2 Z6 h/ ydef forward6(state,isEmpty,currP): # 六步最优0 p4 e' o; Q+ R7 i K) C$ [# u9 E8 b1 x/ ~ g
lists = [] ) |% H @0 u7 L1 ]0 M """ 遍历所有的可能性 """. L* p7 G# [! f& a; `- _+ E
if currP in A: # 如果当前在第二道工序CNC的位置( p' @! x- O6 ]! E
rgv = 1 . P; G2 O2 Z G: n8 ]/ F for e1 in B: 0 S/ n: `. p& s$ x for e2 in A:, ]1 f: N: [( ^- [; w5 K K/ P
for e3 in B:' B4 q0 L3 g+ C/ e
for e4 in A: ' A* c# Y7 g3 m6 V" y( I for e5 in B:3 O* C: I$ X, A* L8 @
for e6 in A: 9 w; a+ z1 u; k' }. u. {: Y! J lists.append([e1,e2,e3,e4,e5,e6]) . h% N5 ~- M5 ]! N else:+ \7 \1 Q- j' ^- |3 k
rgv = 0 * x7 N7 V+ z7 B7 X% n for e1 in A: ! \$ Z0 R- L/ @: z for e2 in B:. U# P, W9 }5 N2 c
for e3 in A: }' V z9 Z; V4 p
for e4 in B: 1 w/ P4 l0 a5 W for e5 in A:. q# }( Q r6 a" V) P. D
for e6 in B: 4 c7 u# ]0 U, a* \ lists.append([e1,e2,e3,e4,e5,e6]) : u2 _! E; K# q minV = 28800 6 {# e5 q g7 |0 _& k7 ` for i in range(len(lists)):1 s* B: h5 U- w" J3 I9 t K( o& z
t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]+ M. @: E- i2 [
if t<minV:, s: H, S! R' E& A3 L/ X5 B( o
minV = t r) F% d+ b7 O8 {5 ~ I
index = i% D( s( `* M1 ~ o+ s' n) V& d/ X2 B) D
return lists[index][0] # 给定下一步的6步计算最优/ t4 U: W( H3 y) B% D% n
8 K' W8 N! c: H' j9 ^% w3 x. ~def forward7(state,isEmpty,currP): # 七步最优# {1 }) O4 d! m, ^% ^) K
lists = [] 4 W# n# l! U. o( @ """ 遍历所有的可能性 """, V( M! |/ T( L# l
if currP in A: # 如果当前在第二道工序CNC的位置) {; ^( r( f s; m
rgv = 1 . _! l2 \) B* {7 V: |4 u0 P3 F for e1 in B: ) z- G! E$ I2 y+ k. N; a( p8 I for e2 in A:. |% N6 B. s7 M# c
for e3 in B: ) J: o6 Z, d, e6 ]7 j for e4 in A:- A- m1 g {+ D) H7 g0 N
for e5 in B: 1 T4 W, D# r4 f/ E8 C4 u- c, ~ for e6 in A: ( O/ n* v$ r7 Z7 X; m for e7 in B:5 X, y7 q6 w5 V6 U( K0 L
lists.append([e1,e2,e3,e4,e5,e6,e7])7 @0 u% U9 s6 Y) m. W) W1 P
else:. r9 {9 ?9 Z% _7 O6 b/ {2 U
rgv = 0 : |- u0 S+ y; j* E4 I for e1 in A: ' ]" D- F. }2 E/ d for e2 in B:! e4 Y) o5 a' Q& I
for e3 in A: 2 C# K9 D/ P' m# ^: z for e4 in B:' ~' K. V, D7 F% C) B6 N
for e5 in A:9 ~4 k+ X5 z$ z/ W9 z
for e6 in B: 3 C/ ~. B; [6 q) O$ T for e7 in A: 5 J/ [' q1 P5 s3 G- ]8 d lists.append([e1,e2,e3,e4,e5,e6,e7]). ?: b* J' d" b4 ], m/ h
minV = 28800 + Z6 b" }& j" J, v; g& R for i in range(len(lists)):% _; Q3 B. C" }+ ~
t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]- ^; c6 x E5 {' p5 D2 K+ r
if t<minV: 6 G; w+ j4 ~9 o# Q: g. _ minV = t $ c6 d4 j( W6 f h; Z7 B& ^ index = i2 Q8 F" N2 F! t4 t2 q/ ]
return lists[index][0] # 给定下一步的7步计算最优% d8 a; p1 x9 j
5 m& ]- J0 I5 _7 c/ n: f
def forward8(state,isEmpty,currP): # 八步最优 1 u+ Z$ S3 [1 @( n lists = []8 I. s f. b5 x0 m5 [/ M
""" 遍历所有的可能性 """+ {7 d2 D1 t h' t# |. z6 C
if currP in A: # 如果当前在第二道工序CNC的位置 . x" i& F" U' C7 D% y& ~ rgv = 1 0 F) e+ b. d# U1 B for e1 in B:! S. X% K; s* {; E
for e2 in A: - l' [( `" p* y1 v: S: C( w, O for e3 in B:2 P0 r/ c' S1 B, g* X% A
for e4 in A:( V+ b, U( h- D# o& @' E
for e5 in B: * M7 p- |3 U- X' {" z/ v3 ]2 Y for e6 in A: / g6 T5 R6 P( _/ _- y for e7 in B:) p7 U9 \9 e$ ]" i Y& q. d9 D) Z
for e8 in A:) @- x! _! y% ~7 H, B6 g
lists.append([e1,e2,e3,e4,e5,e6,e7,e8]) 5 ^* H- X+ p1 h. S- y else:7 q) ^4 x! [; S) X& h, R% n; {
rgv = 05 j1 ~5 i. D1 B! i# v
for e1 in A: 5 l% y9 \ d+ I1 T) ?( A8 G for e2 in B:5 r4 P; z/ _$ B( R
for e3 in A: 8 z( k ^9 B3 L7 F. r, ~ for e4 in B: F% e! i1 n4 Y0 r V5 _! q+ V for e5 in A: , W* S9 f4 h7 U( T+ g0 W$ J for e6 in B:9 w$ y: r9 p. V- v* a
for e7 in A:: j) {3 R4 I; L Z4 m7 h' a- a: b% a
for e8 in B:. e4 J1 j* K4 x4 h9 C
lists.append([e1,e2,e3,e4,e5,e6,e7,e8])- Q5 f$ f0 M2 ?9 r1 p; D
minV = 28800 % z: u w# D# t: Z for i in range(len(lists)):9 ?& O3 W( x- o9 K, X% ?3 V [9 S
t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]# x+ N: h0 M+ c) V( D, |
if t<minV: - [. E) H' t1 S5 ]$ g8 p, l minV = t 1 S4 d& z7 p, X1 N x4 O: T/ C2 s index = i$ x9 i) r" O% [& t7 u0 M. P. E
return lists[index][0] # 给定下一步的8步计算最优 & ?* ]( u8 B1 s1 K) w" S+ y) a0 S. J0 _
def greedy(state,isEmpty,rgv,currP,total): # 贪婪算法 ; B% W7 S" F q9 W! h line = [] * q+ I. z- G' S3 ]* h- k& k& H" q count = 0 . v: I3 V3 i" X( Y) c$ N while True:4 A' e) N+ Y% M( d
#nextP = forward4(state[:],isEmpty[:],currP) 4 d, v: U* y% A8 W
nextP = forward5(state[:],isEmpty[:],currP) 9 i& [4 z% Z% Z' p+ i3 L2 c* P" \ o, A line.append(nextP), m) t7 y/ f' L2 R, l4 @! H$ K( H; x
rgv,currP,t = time_calc([nextP],state,isEmpty,rgv,currP,0) ; A5 C* n. W1 ? total += t # b$ p+ d$ D3 _+ q count += 1) x" P. h$ g0 W) z7 m
if total>=28800:9 o1 c4 {4 O. a6 a" M+ [( x
break ( u1 \# ~7 f5 H. I return line - v& a$ o3 K+ E& `# R : o6 D7 d% f; S6 q- e* c# lif __name__ == "__main__":' v6 X2 m& Q8 \5 d6 r; B6 w7 W+ j
state,isEmpty,log,count1,rgv,currP,total,seq = init_first_round() % C7 X j( k/ C2 t- F! ~ print(state,isEmpty,log,count1,rgv,currP,total,seq)$ L8 q8 z$ e( @6 W, B2 i
line = greedy(state[:],isEmpty[:],rgv,currP,total)( K/ U+ h9 w( J+ O
simulate(line,state,isEmpty,log,count1,rgv,currP,total) 7 ?+ S1 e* F0 | S% e & `# c* X8 B6 M' \3 t
write_xlsx() 1 _( u" W* |; D% U' C; c; H/ Z后记 ; e! j+ W- g1 S x" Q# k5 Z V7 h& B这次博客有点赶,所以质量有点差,很多点没有具体说清楚。主要最近事情比较多。本来也没想写这篇博客,但是觉得人还是要善始善终,虽然没有人来阅读,但是学习的路上还是要多做小结,另外也是万一有需要的朋友也可以给一些参考。虽然我的水平很差劲,但是我希望能够通过交流学习提高更多人包括我自己的水平。不喜勿喷! / X( n' u- g4 [2 a x7 ^+ I; W) w--------------------- ' _0 n' w0 e% f+ ], L : X$ \0 U$ Y* a0 P# ~: R ( D2 b7 _; L t% n4 t& ^; x. g; Q: i. t; C1 d- i% s