: ]; Y8 s X: a# A( ]3 F0 P I M言归正传,本文主要介绍我们小组解决2018年全国大学生B题的思路分析,不代表标准答案。当然我还是有自知之明,本身水平不是很高,再加上三天时间限制,自己做出来的模型以及算法肯定是比较差的。这里仅仅从我个人的思考角度出发写一些参考思路作为分享讨论,希望各位读者朋友轻喷。$ X+ S& z/ a3 S' _8 r$ E. g
c7 }, M7 I* |0 Q4 }; A问题分析 ' [! E0 |5 X7 U+ h+ S4 _ M: m8 X9 X% a8 E, n1 V
今年的B题确实与往年有很大的不同。往年的数学建模问题往往具有比较好的开放性,问题解决存在较大的建模空间。今年的B题的题干本身就几乎是一个明确的模型(8台CNC+1台RGV+CNC定址),加上第二道任务要求我们根据给定三组数据完成八小时内的RGV详细调度方案,并写入四张Excel表格,给人的感觉就是要求我们去完成一道填空题,然后附带写一篇论文[尴尬]。 $ W4 S. o7 b+ W% w p9 k. e& u& K8 E' B( b
为了方便各位读者对赛题的阅读,这里给出链接:https://download.csdn.net/download/cy19980216/107087255 _: X5 L/ \2 ^# ~5 E% Y- K0 Z! x
/ `4 f5 J9 \( Kdef update_state(state,t): - X, e7 G/ m' d9 ] length = len(state)) l) q' n2 @8 r6 m
for i in range(length):* b* x& j- s3 {( g
if state < t:* } H; q, N. t- W7 a' O! @% G
state = 0+ f+ o# _8 G/ j5 {
else:& F6 h0 ~8 P. K/ A3 Z" d# `
state -= t7 h4 H+ ?. Q _0 k
return state - Z% M$ v: u! z& R1 y # e! L7 f* P7 A6 ?0 {! I0 y3 \def time_calc(seq):. U4 J$ a' T1 S1 T! b( X. q6 w8 x
state = [0 for i in range(8)] # 记录CNC状态/ l) C* x/ o8 E' _7 P/ u7 j
isEmpty = [1 for i in range(8)] # CNC是否为空? 7 m+ g& o6 M0 G Z" o currP = 0( X) u8 o( g: { ^- m: @+ d c/ `; P
total = 0 ; i) W3 B/ \9 |: D5 E length = len(seq)# u. S' {/ |* X' E4 Z& f
for No in seq:% e v- H4 ~& D: a
nextP = No ! w* Q6 ]% t' }9 b t = tm[currP][nextP] & B2 l% k! i. w1 x7 D total += t # rgv移动! x9 g' U T/ }5 ?9 V* l3 r
state = update_state(state,t) # 更新state/ v% _/ v# @' \* B- Q
if state[No]==0: # 表明CNC等待 `/ G$ E4 e, N2 `# X8 s% K1 g5 Y if isEmpty[No]: # 当前CNC空/ z6 G0 ]* S) ]( l+ h: J
t = CNCT[No]( o- ]& b5 m. D! `5 [
isEmpty[No] = 0. ^. b0 v/ s* C
else:& N/ [! q" Y- n# e. V% `$ h1 F
t = CNCT[No]+Tc 5 {& a0 K0 c0 U, z4 s, J. l total += t* s: u, y- S* j* C+ M* Q3 I
state = update_state(state,t)1 s( R+ {1 V3 x( l' @, z
state[No] = T6 Y' s9 p4 w+ W$ o, t' B) g" M2 v
else: # 当前CNC忙 ' _; r2 s1 S* @# u total += state[No] # 先等当前CNC结束 0 s& e) K+ v0 p" y- d state = update_state(state,state[No]) * F! Y$ T0 N2 _& q. s1 e( Q- w; \ t = CNCT[No]+Tc $ i- K4 Z( G1 U# }+ b total += t : v4 {3 A# U" n9 }' ^0 q state = update_state(state,t)$ ~6 B. ?8 B3 \% G
state[No] = T3 _: T4 e, S6 s, b+ \+ ~2 m
currP = No- A9 v6 N1 g" O- j1 t q2 i& o
total += tm[currP][0]" \9 i3 R% y V# ?
return total6 Z$ P8 `7 b! l' Y4 ~
, o& _2 D$ M1 d0 ]* G- ^3 S
def init_prob(sample): " t/ l+ c. L* B% S9 f prob = [] - A$ ] X6 {. F% @! i# I0 Z% w for seq in sample: 9 Z+ n W5 \ X/ l1 m4 \ prob.append(time_calc(seq)); B: u+ N; U. V
maxi = max(prob)# j/ w! P/ K7 X, c4 t, W0 R/ T: n
prob = [maxi-prob+1 for i in range(N)]2 y' o+ V4 o1 N. H. B. U
temp = 0 $ A& w/ g2 h: r' B% M) u* k for p in prob: " i7 v# [+ f4 Q# w2 ^& x; F temp += p , r' K- U. V; G prob = [prob/temp for i in range(N)] + z. p9 n- A; [8 H( t for i in range(1,len(prob)): 6 b$ E* m* D9 m% {# K prob += prob[i-1] * w7 ~* c3 u8 K" \$ i. u0 J8 \ prob[-1] = 1 # 精度有时候很出问题! Q( z: P5 N9 W4 b8 D+ l6 D
return prob9 U3 i* _+ |' K$ _' E& ?
3 p! w1 b' K/ j* u! G) \8 ?& W
def minT_calc(sample): # K; h) I% t0 j, k minT = time_calc(sample[0])# t9 p* O4 i0 R6 X- r4 p
index = 0 ) ~1 g3 S+ ~; {0 b for i in range(1,len(sample)): 4 Y# t( j" _; c0 \+ L; e t = time_calc(sample)% G! Z9 W6 P0 ~- I
if t < minT: : {0 J' z2 `' g' o( k5 } index = i 9 X/ M+ o1 n7 q$ G) |2 | minT = t & r0 X7 Q5 [, T return minT,index 1 ~5 u5 X7 ]5 \: u . P% y# g' D( T4 B) p; b! ~/ gdef init():' J" a6 J9 s1 L) J& {* t6 C8 }
sample = [] + i+ ~& }- a" c" x for i in range(N): 0 C# ] _; u& ~6 N sample.append([]): A( A j& u) h0 K# U! t7 J
for j in range(L): # Q8 v! i/ B/ F8 s( q sample[-1].append(random.randint(0,7))6 B9 |8 N T1 ^' r3 I
return sample 4 B5 S5 Y3 P# {- U! H- x9 ~& Q, _( T. J5 x3 r9 w# i0 h
def select(sample,prob): # 选择; f, t* `( L2 Y' s- P
sampleEX = []$ \$ U; G8 a6 h/ e+ t! l
for i in range(N): # 取出N个样本) {, L+ y2 e1 ~0 E* I
rand = random.random() ' r( }2 I+ Z7 c8 P. g m+ u# z: w for j in range(len(prob)): % R; [) \/ W$ s$ G1 \) ? if rand<=prob[j]: 7 U$ j' v( y4 r sampleEX.append(sample[j]) / {% }6 h# w' m; q9 s break) b! q0 |2 G. h$ @& k
return sampleEX ) w# z. j3 r- n2 v6 { b3 H) z+ V K3 d. e/ G1 ]; g$ _
def cross(sample,i): # 交叉 " n3 Y( K! L4 L5 Z4 w for i in range(len(sample)-1):2 {5 }+ e$ T% s* ^ j( `' j% t
for j in range(i,len(sample)):! A: {( k7 }% w; B
rand = random.random()) E0 N! f. Y, j: Z; P
if rand<=croP*(e**i): # 执行交叉 % F, X* |8 |, v* U; ~. N loc = random.randint(0,L-croL-1) Y* g( I! K8 Z- Y, D+ w8 } temp1 = sample[loc:loc+croL]( \4 Y! B8 s, o
temp2 = sample[j][loc:loc+croL] # h) g% O8 K8 n# X, T% r! y' N for k in range(loc,loc+croL):5 H- @7 r* t0 b
sample[k] = temp2[k-loc]) d) v" _1 P& q7 I3 ^6 J# h
sample[j][k] = temp1[k-loc]+ b P: W6 |5 O
return sample + U8 y6 } ?. Q# ^2 C ) O" u3 k! Y( J1 }& n6 U
def variance(sample,i): # 变异算子 7 p7 T6 e0 K: Y9 u4 F
for i in range(len(sample)): 6 y9 U( Q; _/ t9 j rand = random.random()' l6 |* Q0 M' ?, L
if rand<varP*(e**i):6 Q* J* G4 V# c& J4 f; V
rand1 = random.randint(0,L-1) . B1 m* L+ |( I" C# D2 V/ g( ` rand2 = random.randint(0,L-1) - ]" I2 B# P5 _" Y! z+ U3 J temp = sample[rand1] $ r! w/ P3 }* d" O$ R- p" z sample[rand1] = sample[rand2] ( V3 A) T; D( U& U9 {$ Q sample[rand2] = temp- N- k( c/ ^: T5 @
return sample5 ]! p. [& W! {1 m2 P
, M- P4 v @% a3 P0 Xdef main(): 2 }3 {2 S4 A0 T! ^' _- ?! M sample = init()2 R# g" D$ A ^' L
mini,index = minT_calc(sample) & } b4 B* y7 N best = sample[index][:]# C3 C; _: t: j5 { q/ }; s# T+ j
print(best) ) C) E# X$ P# Q5 L8 x for i in range(10000): 0 p8 O% V) N6 w9 F0 l print(i,'\t',minT_calc(sample),end="\t"): z7 |' a! I% T, K6 a0 Z+ ?
prob = init_prob(sample) + b, { \, n4 W! G+ ` }2 E0 z sample = select(sample,prob)0 o9 l3 Z8 @) S/ ?0 @* C) q
sample = cross(sample,i)) s& _5 ?2 {6 i
sample = variance(sample,i)4 S' L& ]2 I# p/ v( P8 x
mi,index = minT_calc(sample) 7 F6 k+ d* K* |) p. t if mi>mini and random.random()<e**i: # 精英保留策略( t. n( m; |/ Q/ }0 x5 y
rand = random.randint(0,N-1) 8 A' H1 D1 w' l sample[rand] = best[:] ' h: H) c0 o& H9 L+ G. @1 \ mini,index = minT_calc(sample) 7 L/ x4 p Q: a best = sample[index][:] ' [3 e! `! Q( Q* e6 k4 d K print(best)( a6 u% C0 q% s2 I" C
print(sample)( N% X1 H `7 H5 y
" z, L/ u' _8 k- O7 X5 v
if __name__ == "__main__":6 S e3 L0 x% a) U( a4 q
main1() 4 f% Q9 t2 l/ z """ 穷举搜索验证 """ % g; M% p1 G6 `0 _4 R a = list(itertools.permutations([1,2,3,4,5,6,7],7))! x0 n; M8 O4 o8 R" W" d4 t6 _
ts = []/ n( m+ A5 M K, ]
first = [0,1,2,3,4,5,6,7,0] 4 D. c5 D2 G1 d for i in a: 7 s) }+ o; d( U& } temp = first+list(i) 7 R0 e( J7 h$ e1 ]( N9 S5 C temp.append(0)) \ ^; U. M2 W5 L" [
t = time_calc(temp)2 R& a# n7 ~4 h% M/ L0 k3 ]
ts.append(t)8 F5 a2 r9 Y( A! E# k; C5 j0 Z7 O
print(min(ts)) ! L& F, m, f* k0 h/ [- d8 c: j3 X. u print(time_calc([0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0]))9 t0 C- ?. e$ m) W% ~0 R
1 M8 b& T' \: n5 v' e4 x0 L, z2 B1 z: {& z. Z/ m
一道工序有故障 0 X' B! R% c# x* a# ?- z 7 E2 F1 C. Q6 d3 m这部分是学姐做的,学姐用了偏数学的思考方式,仍然从循环的角度去考虑,主要考虑故障发生是否会影响当前循环,是否需要建立新的循环。因此就没有写代码处理问题了。具体的思路我确实不是很能讲清楚。但是这里面有一个非常大的问题,就是如果出现多台CNC同时发生故障怎么办。关于多台机器同时发生故障的概率,我们通过估算认为以给定的三组数据8小时内会出现这种特殊情况的可能性大约为30%。这个问题是我无法很好严格处理的(当然如果用贪心算法也就没这么多事了)。 " @/ t- I* U3 [! I; U1 @5 F) d) }) s: _4 s/ K5 p! y& K/ R" }2 i
两道工序无故障 & 两道工序有故障 + \* h9 A9 |( r/ {0 a& U ; b4 z( U1 C; h$ p" P. I6 m这两个部分都是我来处理的,因为使用的方法大致相同,就并在一起说了。1 l) [% a* s* ^7 S) N8 I; I) i
. I0 P2 L* c( e$ t, \/ s两道工序与一道工序最大的区别在于三点: 8 m7 z/ ]9 W4 o& H/ v/ k ( v6 [4 ~& u7 \ B% w7 t" U# X1、开始要处理CNC任务分配:分配给第一道工序几台CNC,分配给第二道工序几台CNC?具体怎么布局?% m9 y8 q n6 i7 h
+ \, S. S* {, J, R+ K/ P
2、加工过程可能仍然是一个循环,但是这个循环将可能会非常的庞大以至于不可能直观的看出来。 ?0 ]/ Q* y3 x5 [9 f8 ^* X 5 _, L; g I& K$ H3、两道工序的分配已经是一个严格的NP难问题了(即理论上无法在多项式时间内求得最优解)。2 C$ j: P6 \+ ?6 q6 ^9 ~
. U+ |3 J1 |& B" z: ]! ?+ F+ G
第一点我的想法很单纯——穷举,没错,就是穷举,除了显然不合适的分配方案外,其他方案都试一遍(虽然真的很蠢,但是我真的想不出到底能怎么办了)7 t8 @" l* }' o# }
5 s# b. w1 @* s
第二点因为不存在循环则使用遗传算法需要设定一个相当长的染色体长度(我们设定的染色体是RGV为各台CNC上下料的次序,如果要考虑全过程的模拟退火遗传算法,则染色体长度大约在300~400左右)。事实上我也尝试了这个方法,结果从我写完这个算法我开始跑,一直跑到比赛结束算法依旧没有收敛[捂脸]。这里给出代码仅供参考(各位朋友要是有好意见也可以提出) ↓↓↓; ~8 O9 s1 ]0 L& G& V
( m c( ^ p5 w6 @2 G
# -*- coding:UTF-8 -*- ( N1 ?8 o7 }, n$ Z; S0 Y; ]"""' B% C1 A1 P$ a1 ^; f: h
作者:囚生CY4 X7 y$ h6 V: s! d$ y3 @0 p
平台:CSDN4 a2 O* Z; |6 U2 z$ z* a7 D
时间:2018/10/09 . }9 l0 ]6 }1 _1 g! m2 e 转载请注明原作者 $ c5 i1 a4 }9 n5 z; j8 x6 T5 D 创作不易,仅供分享 9 m3 D0 [& w" N b {"""$ T' a% k( M- j8 o
import random % y8 ?5 \. N4 x+ \$ a$ \3 V! I6 H2 ~& T. _
# 第1组' \6 y4 H q) n$ h0 x) U
""" $ }) v& H& r9 `; }d1 = 20- J0 \ p% y9 D: y
d2 = 33 # [% \ w9 b2 _9 O* A* J+ _6 ~& w Sd3 = 460 K0 b4 E y) N% l4 s3 d! ^; p
T1 = 4002 e! J/ [# C" k/ Q. c
T2 = 378 + P0 z8 w# |; z! {To = 28 $ Q* g' o+ @2 v+ }1 N1 I8 eTe = 31 + L, b' t6 `5 n9 oTc = 256 g3 t6 O. @4 \9 W4 g/ p1 x$ [) e
""" 5 `0 W. N. x H% E5 h- L i2 A+ N! V" I$ y& L
# 第2组 & I0 T- k% Y" \& c& L""" \: _- E! l1 f( o7 T0 d/ o0 B: Ld1 = 23 - r9 Z% h4 N+ n* Cd2 = 41 - a4 m$ j% j1 vd3 = 59 : ?9 r0 U& [1 P' S/ ^T1 = 2806 d4 s; Y( J$ j9 d. v6 P
T2 = 500* n' \2 f$ j; d/ @( r
To = 30 * ~# y& g5 V) {0 R. cTe = 35, p' L2 \" z ?6 A" g: l7 G
Tc = 30, j1 d# q: p$ o! u# C; N
""", S1 y. O @7 p) h& [/ q" Q1 a- C0 g/ ^
3 i2 \0 K& J3 i3 |/ V& y6 H# 第3组/ _. t9 |/ w1 H+ ?" [8 V2 Y
d1 = 18/ W9 u" a0 m' Y6 j6 S4 H6 j
d2 = 32 " ~# n+ a0 ]! z. Ed3 = 464 f% T& K6 B$ h
T1 = 455* `$ m/ ^( r: r& x \: m, j2 Y
T2 = 182 7 j( {+ E$ F# XTo = 27- s! ^3 Q0 r! K( j
Te = 32 ! ?6 G1 P8 x% bTc = 255 m: [ |% {1 o% T a" O' k7 V
+ u; a y3 _2 DcncT = [To,Te,To,Te,To,Te,To,Te] 3 |$ p; z6 Q' Y/ ?1 q9 B4 |tm = [ 0 h# h, f; u. O( J( O; R [0,0,d1,d1,d2,d2,d3,d3],+ {2 X3 K" W, \* i$ d
[0,0,d1,d1,d2,d2,d3,d3], R) C+ V! \3 \: o1 Q8 k) m
[d1,d1,0,0,d1,d1,d2,d2], 5 L& a# u% k: C. R( h8 q W* C [d1,d1,0,0,d1,d1,d2,d2],7 L2 Z. d$ W: n5 e
[d2,d2,d1,d1,0,0,d1,d1],/ g8 H( R( q2 k$ G$ I: c* k
[d2,d2,d1,d1,0,0,d1,d1],8 T' g8 L/ N; ^+ b# X
[d3,d3,d2,d2,d1,d1,0,0],( F5 T8 Y, z% L9 w$ a p: b
[d3,d3,d2,d2,d1,d1,0,0],5 o$ r Y: I# L2 \2 w
]! C; m# J/ K! e
Type = [1,0,1,0,1,0,0,0] # CNC刀具分类: `$ s" ]) |2 [( |7 L: Y/ \
0 C; l/ F0 J% F; G# `5 T1 o
N = 64: U$ H; M0 G6 r8 d/ N2 R
L = 100. M+ f2 \( p- _3 i( W0 h
varP = 0.11 v. P# i' B/ p r/ K% T' L) }
croP = 0.6$ S2 g9 K" G- Q& P
croL = 2" o& Y' N0 p( \' ^2 v
e = 0.99 9 K; ] B T) k2 O % L$ `4 ^$ y1 I7 {; bdef init_first_round(): # 第一圈初始化(默认把所有第一道CNC按顺序加满再回到当前位置全部加满) . _! s9 `) D( \2 N% K state = [0 for i in range(8)] # 记录CNC状态(还剩多少秒结束,0表示空闲) . O8 U0 J% W' D# \: ~0 g4 A! f isEmpty = [1 for i in range(8)] # CNC是否为空$ J! h* U4 [: w
rgv = 0 # rgv状态(0表示空车,1表示载着半成品) & |6 O! B6 @8 f* A6 W6 b, s currP = 0$ T- }+ g+ L2 J3 ]% V
total = 0 4 F) v5 D+ [; `" G seq = [], H# l5 R- h$ n' ~- O
flag = False 8 Q8 B% q5 Y5 j3 g9 ?0 {; p for i in range(len(Type)):6 N! X5 |8 w) n" I, h" \ K) }: U
if Type==0:( F& w) g' C1 f1 m1 ~
seq.append(i). ?( T, N& s8 K5 Z* Q
flag = True! ?2 x0 y. K) k1 ?
currP = seq[0]% Q8 S3 [& Y2 X7 j3 ~
seq.append(currP) ^$ L- Y5 X" j rgv,currP,total = time_calc(seq,state,isEmpty,rgv,currP,total)! F+ M; m1 O/ }, }# S
return state,isEmpty,rgv,currP,total,seq 8 O7 f' V6 f6 i. Z! }+ }7 m( o0 \& b1 L' h$ [9 V
def update(state,t): 8 P8 d. L7 F; w7 K for i in range(len(state)): ' s* m* S! x" m L2 R if state < t:5 B6 S" h% y0 c0 V, {' c
state = 09 ?2 M" h" N2 W; w2 o- L" K
else:+ I7 k# }: p$ n# J% y
state -= t ! L$ `8 S! ~& q# E& r2 u6 ]" ~& c; A
def time_calc(seq,state,isEmpty,rgv,currP,total): # 事实上sequence可能是无效的,所以可能需要 9 _+ d/ R6 b- ?0 J- F$ U# l3 d index = 0 ! k3 P# D& k4 C temp = 0 8 W: C& G3 ]6 d7 F2 m7 C while index<len(seq): }4 h) A& L3 K5 s """ 先移动到下一个位置 """ ! K9 m1 V# \( O0 V, ^* [( ~ nextP = seq[index] ' {) j2 L$ M0 h( R8 ` t = tm[currP][nextP] 5 K* M/ E4 ~/ x: N0 P. _ total += t: b1 b3 _1 a9 Y& X
update(state,t). h* t6 Q# e# _( x! S, T4 u
if Type[nextP]==0: # 如果下一个位置是第一道工作点 8 ?7 f% Q p- {& a if rgv==1: # 然而载着半成品 5 c. z6 e# F5 ^& p5 D! g seq.pop(index) # 去掉这个元素并中止当次循环进入下一个循环 ! m$ O6 ?$ r4 ^4 ~6 M5 ` continue $ b; \6 ?' y x4 _7 Z
if isEmpty[nextP]: # 如果下一个位置是空的 ; T z% \7 q) O2 A6 [ t = cncT[nextP]! P! T m$ G! p9 p3 X
total += t 1 u* C1 P$ I9 O+ B7 n& C update(state,t)6 K+ r' l3 |4 e% C( X& S7 ?
state[nextP] = T1 # 更新当前的CNC状态3 w! ^0 B3 p7 a: n4 S7 O$ w
isEmpty[nextP] = 0 # 就不空闲了 * ^$ c2 s. r1 y7 x2 M. C* |, Q else: # 如果没有空闲) r( z! [9 b9 K) ^1 g7 x$ z5 L
if state[nextP] > 0: # 如果还在工作就等待结束 0 d* J" F8 p" _, C, Q7 \! Z# g t = state[nextP]- |; l2 V j0 K5 _8 r
total += t1 R$ J9 Z: J! B
update(state,t) 0 C* T& i0 k* `( {) T! J t = cncT[nextP] # 完成一次上下料 / Z. L9 ^, c9 j" }4 a, C total += t- Y& B% o6 R+ u; R& w4 T/ V
update(state,t)% f- n6 p+ ~5 ^9 G9 t" q
state[nextP] = T1 , n2 {# h r+ b& x, s; F! N rgv = 1+ p6 ?0 T" p8 z6 w' [
else: # 如果下一个位置是第二道工作点2 ` O4 S. U" p1 S5 p) x
if rgv==0: # 如果是个空车 * A9 n) m: e0 l% K% k# F. w* b {! q seq.pop(index) # 删除当前节点 1 f! Z# N/ E9 ^2 x; [$ Y continue, f% u: n& N t* ]
if isEmpty[nextP]: # 如果下一个位置是空的 8 V5 w0 k5 w, r( m; J t = cncT[nextP]5 r/ J6 q- Z" q# Z8 |
total += t" A* E! e9 m; P5 f2 g8 a
update(state,t) 5 o' w$ ]9 u3 J! Z. @ state[nextP] = T2. _8 v( b; @% W' d0 O
isEmpty[nextP] = 0 # k: w& K$ `+ d
else: # 如果没有空闲* h+ Y" k. W9 ?) T
if state[nextP] > 0: # 如果还在工作就等待结束1 ]6 r1 [! M0 |$ X" J4 R
t = state[nextP] 0 K8 A9 l6 l7 A+ b- Q" U total += t 4 L# _" ^( b8 U update(state,t)/ Z# @' ~) I" z2 S
t = cncT[nextP]+Tc6 S5 f# w# m3 E. j6 r
total += t- z& e E- K- g8 {) I% G( P4 o
update(state,t) ( P9 ^! C- G. @- y1 g+ e6 v state[nextP] = T2 ' H+ ^6 k. P1 N( z rgv = 0/ q4 f1 k' y+ T# v5 [ z
currP = nextP# x5 J# ^; G5 J- v6 F8 c% ^
temp = total - k3 k! t# v. t
index += 1 1 k' @! o2 }7 @' c
total += tm[currP][Type.index(0)] # 最后归零 u0 ~6 u7 f e* h0 P return rgv,currP,total. F: I$ J, l5 m6 I. d6 e$ Z% Q
9 q! O5 k# F. sdef init_prob(sample,state,isEmpty,rgv,currP,total): # 计算所有sample的0 a7 n) N2 W* g3 t. B
prob = []1 }9 s9 T3 T: J9 g+ p# i
for seq in sample:3 x7 s7 o# ?' T: }
t = time_calc(seq,state[:],isEmpty[:],rgv,currP,total)[-1] - M" n. J+ p0 [8 Q w prob.append(t) & d; P) D7 a0 ]; P. T: c maxi = max(prob) 8 }0 F0 P1 X, W- c2 F# f% a8 c prob = [maxi-prob+1 for i in range(N)] " i9 T J* S" {7 J0 t temp = 0 ( S4 E5 \" q6 m5 L$ M8 M for p in prob:$ G' y" L! {; T( Y* I$ J
temp += p3 U E H5 y4 {( M! q5 @$ X2 k3 D) p: o
prob = [prob/temp for i in range(N)] - z0 L- t: _7 W) e- K0 t for i in range(1,len(prob)):2 ~& J7 u, I1 V
prob += prob[i-1] 7 Z+ G. B E$ q/ [! }) w7 E1 G$ h i prob[-1] = 1 # 精度有时候很出问题$ d' ?. S L& s8 p" [
return prob " u4 D/ W: d' J- m p0 u" v- z6 t* e- ~/ \
def minT_calc(sample,state,isEmpty,rgv,currP,total): 1 V( E, [2 ~6 c3 c1 u9 h, q. [5 z minT = time_calc(sample[0],state[:],isEmpty[:],rgv,currP,total)[-1]2 ^- ]( @; ]3 l
index = 0 ; r" |+ p1 W9 u+ {1 Q( h for i in range(1,len(sample)): ( @" {; B7 j- G5 ]* V7 L$ ] t = time_calc(sample,state[:],isEmpty[:],rgv,currP,total)[-1] : {1 k/ J5 M* _* D, r if t < minT:% n; G& j. l- v) F8 i+ p# G" f1 r( n0 Y4 g
index = i 6 C2 E! b+ I2 _% P; q minT = t & `, R: _( C0 } return minT,index: o+ W$ K" g$ _) l6 r
. i. @0 `" |3 K- o7 Gdef init(): # 初始化种群(按照第二道工序,第一道工序,第二道工序,第一道工序顺序排列即可) Y, X: }0 c9 Q' P O sample = []4 H7 T: {4 A- R4 k$ x6 |4 p: h9 ^7 _
refer0 = [] ! F" H/ [3 E% G. \7 j+ @* p# H refer1 = [] $ v0 h4 t a* q- a' @ for i in range(8): & u C; ?* C0 Q2 t; G" S if Type==0:$ ^' s, k- L& D
refer0.append(i)7 H" E6 N6 F' V& V8 D
else:4 C" h4 t8 u5 S. I5 ^3 H
refer1.append(i) ' Q: I1 c0 R0 k6 Z% j% [6 E/ G for i in range(N):" C; n7 ?/ r0 N
sample.append([]) , j% s3 z7 n8 G: m8 m$ n for j in range(L): J, S. ~0 ?9 K, B! N3 p3 ?
if j%2==0: 4 X9 B U: _% X1 s- H8 F, v sample[-1].append(refer1[random.randint(0,len(refer1)-1)])( u( ?1 E( k* E3 W7 K) p. W& H
else: & U. w! h9 Y+ D# a sample[-1].append(refer0[random.randint(0,len(refer0)-1)]), Z0 }. \& K2 x
return sample& o+ @+ r3 o% ^2 B6 e; a$ W$ X
^+ X' E" r4 H9 i4 k$ G, P! R- B
def select(sample,prob): # 选择算子' a1 X7 g; P( m1 w
sampleEX = [] 8 |6 h1 O1 U2 Y1 f; Z0 i for i in range(N): # 取出N个样本 " o. V4 E7 ^" y; o. B- M rand = random.random()& p2 H! L, p5 n" m9 u6 S
for j in range(len(prob)): # v; r9 |2 K9 |! X t) X- q2 @ if rand<=prob[j]: ; U4 J3 G. ^0 u- A6 y sampleEX.append(sample[j])% v1 F* L' q; O
break b ?5 Y5 i a3 U' g; \' \ return sampleEX & D1 `. a3 Y* @) H0 h- _4 m* m0 y; s8 K
def cross(sample,i): # 交叉算子 m3 ^5 W6 ^" z% u! S. _# q$ W
for i in range(len(sample)-1): / T. z* Y# m/ \( ~& D: |& O' O: t1 r for j in range(i,len(sample)):- b6 P3 u ^& U5 s9 L
rand = random.random() + H, D/ |5 d; l) j# G if rand<=croP*(e**i): # 执行交叉 ( Z c2 G; d3 ]& P loc = random.randint(0,L-croL-1) : J, m# s% M7 [: z8 k+ ]9 O temp1 = sample[loc:loc+croL]3 }8 \" k7 G3 F; C( R
temp2 = sample[j][loc:loc+croL] ! L7 [, r4 X3 U, S for k in range(loc,loc+croL): & |0 F+ n# n, | {' K! R4 y sample[k] = temp2[k-loc]0 U" a2 m8 d" |+ b
sample[j][k] = temp1[k-loc] 2 K5 P) U6 B8 d, b( _, d return sample + g3 |3 m6 o: J5 y, u1 |+ q 7 K2 ^6 h e2 k: t% Y) Pdef variance(sample,i): # 变异算子 2 F5 m) q9 m' y% [# E for i in range(len(sample)): J8 O2 n, h/ }
rand = random.random()5 V! k2 h5 T4 B5 i* q
if rand<varP*(e**i):- B) N) v( s2 l: ]8 Z Q& I
rand1 = random.randint(0,L-1) - c% F( |' Z" `! w# [5 N randTemp = random.randint(0,int(L/2)-1) 5 A: I6 i3 J# E: Q0 a rand2 = 2*randTemp if rand1%2==0 else 2*randTemp+1 ) V r2 h3 Q% V/ x W temp = sample[rand1]8 X3 O& c" w. V2 \
sample[rand1] = sample[rand2] " ~, u( s) h4 a# g/ m sample[rand2] = temp 8 ^2 l5 g x3 L& F+ z/ Z1 U) M return sample. a; E2 N8 |# g+ }* h( l
6 q; D: f3 F& Y; d+ j8 X0 sif __name__ == "__main__": $ L* J, `) @- I' P) W; I, c state,isEmpty,rgv,currP,total,seq = init_first_round()' f1 n/ Q2 G* K$ [8 I3 R
print(state,isEmpty,rgv,currP,total)5 h( c& i s- x( ~+ b) v ?' N
sample = init()1 ^) d% q2 A9 \% j
mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) 0 C8 A0 Z$ N8 X% L- g) L4 M best = sample[index][:] 1 G" `% @8 ], A3 j% ]( z& U1 _ for i in range(100000): 7 Z+ E2 N: V/ e1 [ f = open("GA.txt","a") 2 e9 s$ ^- M+ h& s. u- b tmin = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)[0]$ D" c3 X. H, W6 }5 h+ I: X: _3 C
f.write("{}\t{}\n".format(i,tmin))4 n0 W5 E+ P# p! `
print(i,"\t",tmin,end="\t") , `9 e4 ^, P# b z prob = init_prob(sample,state[:],isEmpty[:],rgv,currP,total) & V+ Q: C* D( y- r sample = select(sample,prob)+ b; C1 I# u3 q9 Q& f
sample = cross(sample,i) ' E, j+ k# i! L5 F: t) W sample = variance(sample,i)* |' Q1 i. C" H) s: A& x" v/ v
mi,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) 6 b( M- r1 w c B. Y7 r, W if mi>mini and random.random()<e**i: # 精英保留策略& g& |: c6 g( P2 T; |' M
rand = random.randint(0,N-1). I: @" h; H/ y. L9 l
sample[rand] = best[:] ; O1 K3 x& X. g k8 o$ Y$ N mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)% l _: Z% x4 p( t9 T6 U$ [6 t
best = sample[index][:] 2 j- \% N( W$ t4 a print(best)& |- {8 O3 x: Y0 L# q3 v
f.close()9 @6 ?. \9 S4 T% A, T; p) _
print(sample)* f/ K! z0 ?1 Z( O3 \, l5 i/ p9 c) w
遗传算法这条路被堵死后我一度陷入俗套,用最直接的贪心搞了一阵子,觉得用贪心算法(即考虑下一步的最优策略)实在是对不起这种比赛。然后我就变得——更贪心一点了。 ( ^2 x( C& w0 F1 b3 E% F6 C# c7 n; X6 L# q9 z
我试图去寻找接下来K步最优的策略,然后走一步。K=1时算法退化为贪心算法,最终我们设置为K=4(当K>=8时算法速度已经相当缓慢,而4~7的结果大致相同,且K=4的速度基本可以做到2秒内得到结果)。2 ~ p/ ]2 ~$ M! u7 o. h