, r( Q: s6 v; ~$ N1、开始要处理CNC任务分配:分配给第一道工序几台CNC,分配给第二道工序几台CNC?具体怎么布局? 4 |! X( l) r5 e & B A7 W- _; |1 A) L; R2、加工过程可能仍然是一个循环,但是这个循环将可能会非常的庞大以至于不可能直观的看出来。 5 z4 I) m$ T' y7 H w8 I) d* U. N) C w9 U5 h
3、两道工序的分配已经是一个严格的NP难问题了(即理论上无法在多项式时间内求得最优解)。/ }& \( j' ?6 J. \2 z( n3 g% V
( _+ L, ?# X$ s' S8 s% @
第一点我的想法很单纯——穷举,没错,就是穷举,除了显然不合适的分配方案外,其他方案都试一遍(虽然真的很蠢,但是我真的想不出到底能怎么办了)6 Y! s! _- }. _
1 q) w1 D& e q8 N: `
第二点因为不存在循环则使用遗传算法需要设定一个相当长的染色体长度(我们设定的染色体是RGV为各台CNC上下料的次序,如果要考虑全过程的模拟退火遗传算法,则染色体长度大约在300~400左右)。事实上我也尝试了这个方法,结果从我写完这个算法我开始跑,一直跑到比赛结束算法依旧没有收敛[捂脸]。这里给出代码仅供参考(各位朋友要是有好意见也可以提出) ↓↓↓ $ L3 r6 R( L6 q( K$ P + F0 E2 \. Z4 }6 W# -*- coding:UTF-8 -*- ' g. [5 l& b- V. p8 t"""8 s0 f" C6 q7 l; Q# g/ n
作者:囚生CY , X9 U5 `& X8 q 平台:CSDN# a9 B- H7 B* ?7 C$ \1 X6 t; F- Y( Y
时间:2018/10/09# a: M6 w, {; _ T7 Z1 S
转载请注明原作者; y) N4 }' S+ Z G9 B$ w$ E+ [
创作不易,仅供分享7 x: i! l! g, t7 {! }
"""4 w. K3 B U- t) s, X6 e0 _% w
import random& z: e4 K( Q A' S$ \. F" z
& ?8 l3 A$ O/ e- y# 第1组 ) p. ?! H& R! M6 ?( F' p"""( j2 o8 r; B9 L. i( X+ z
d1 = 20 # Q; ]9 D8 o. _' Z) jd2 = 33 : O5 J* y1 O) j" r3 J- fd3 = 46. z; r6 T* u9 w/ [; m
T1 = 400' i' C0 F) \* d e
T2 = 378* j+ k& @4 k2 n. B- k
To = 283 m& b" R$ m& Y; h
Te = 31 `- x9 X3 | V$ X8 c4 L2 lTc = 252 s& T) L% a2 ?8 |+ d4 z
""" 3 x7 G- P# O/ ?5 e J# ^4 d! ]+ q' `% j$ H( `1 u# K, M0 E4 D
# 第2组; G7 L8 Z8 `2 I
"""! R, b! L5 C$ g1 q6 L8 \
d1 = 23" J, ]9 ]3 R! s0 x/ v
d2 = 41 $ t: n7 i4 e% y4 s: w" Hd3 = 59 , G1 P6 k) I' i: DT1 = 280 0 i) c# ?0 y3 V5 `2 Q! h$ kT2 = 500 & M, b9 N9 o1 R' S# r: Y& hTo = 30 # t, Q7 [5 E; ]4 m: L" \+ {$ f2 i) x2 vTe = 35 8 I. r1 B& l# G! x" m' HTc = 30 * k: Z; D+ p! U+ x' U% z* {""" 3 _ T# X" }7 N5 s$ l$ X% A# K+ ~
# 第3组; h* r, O' B$ M" t7 j' K
d1 = 18 : \9 K0 ?9 E* J9 e- d7 Yd2 = 32% K( n& h: H$ [" Y. s" Y
d3 = 468 W$ ?, p! ~5 ?, }
T1 = 4553 @) U) B0 @# d8 ?& P2 @! a
T2 = 182 9 H6 L0 K7 |0 f' O, R: OTo = 27 0 b# k) z2 ^- o0 vTe = 32- d- T5 ]8 D. q3 k( T
Tc = 25 ! H9 O& h- T% c% P: g: f* W, ]$ o4 f1 r s0 g9 n
cncT = [To,Te,To,Te,To,Te,To,Te]/ K+ [8 f) U+ T; I8 s O b4 g
tm = [ % A- @; X; E1 U; O0 V8 ?6 g% W' T [0,0,d1,d1,d2,d2,d3,d3], 8 ]# h: _6 d- L; ], k6 \4 r& u [0,0,d1,d1,d2,d2,d3,d3], ! t$ D' M- ?) C9 x; z0 \2 { [d1,d1,0,0,d1,d1,d2,d2],* r4 [% l: U- v) N9 I. D
[d1,d1,0,0,d1,d1,d2,d2],, a4 O0 ]! n6 n2 n' C( F6 C
[d2,d2,d1,d1,0,0,d1,d1], * s, c/ \$ ^- y5 x Q! F [d2,d2,d1,d1,0,0,d1,d1],* h9 j9 Y9 k. I4 H
[d3,d3,d2,d2,d1,d1,0,0], m1 y" r( l! J4 A2 Q
[d3,d3,d2,d2,d1,d1,0,0], $ P! d" G) h! ^6 V/ S] ; t; D9 b: v! W8 u. P _1 m3 X) aType = [1,0,1,0,1,0,0,0] # CNC刀具分类& r4 m$ h; a" D
/ Z9 ^' T( X4 \! G. j6 B
N = 64 9 @: ~0 L6 ^/ vL = 100' q+ w) G3 D7 ? Y- D8 j z; _
varP = 0.1 _3 x# d1 v3 ^
croP = 0.6 / E+ W8 Y) Y3 N- Z) F% b7 HcroL = 2 $ i5 T2 a4 V7 G, k1 O- Be = 0.99+ a4 e6 @8 H+ h! H+ h
7 [' A E$ l: d9 m1 Q: g
def init_first_round(): # 第一圈初始化(默认把所有第一道CNC按顺序加满再回到当前位置全部加满)( r6 j7 f0 {6 _
state = [0 for i in range(8)] # 记录CNC状态(还剩多少秒结束,0表示空闲) # T/ z( b( k. E1 \4 t isEmpty = [1 for i in range(8)] # CNC是否为空 - V" j/ |. w& j1 U rgv = 0 # rgv状态(0表示空车,1表示载着半成品) , x7 g; R6 r3 k; o# B; e N: B* N currP = 0 & v) T/ M: d, r& j! g total = 0! m% ]5 e. X% {) ]
seq = [] 9 _0 h ]7 b3 b flag = False / {8 Y2 [. L" q& r for i in range(len(Type)): 4 R9 P% K& M9 z/ p/ m if Type==0:8 O# X' z0 w& ^. q& V: x/ q
seq.append(i) 1 }7 S2 b+ s: @$ M: f3 q flag = True & h& b0 ?% m$ l/ O+ c currP = seq[0] ' y& W4 V9 L. q$ s$ E3 R; b$ W seq.append(currP)- r- y# F5 L: ?4 u9 |6 N9 Q
rgv,currP,total = time_calc(seq,state,isEmpty,rgv,currP,total). `0 s) H! U: n: k' z
return state,isEmpty,rgv,currP,total,seq) m: n2 x V8 g2 E, j
4 c4 S5 M7 A1 s, Odef update(state,t):! }* T* ?- t: e! q7 c' W4 n
for i in range(len(state)):' B6 L9 O0 N1 f8 |1 ~
if state < t: # @# m# Z: y+ w) g+ q6 i% ^ state = 0 ) C( N9 m# j6 I S4 h6 \! N' d* z. k else:. K% C H6 e1 f$ Q
state -= t6 Y' E. u# S- ^; v4 a* _1 m
" x/ L2 t3 e8 {* d
def time_calc(seq,state,isEmpty,rgv,currP,total): # 事实上sequence可能是无效的,所以可能需要 4 e3 Q8 }5 F0 ^: c( N index = 0 % P9 d* e3 K! I8 W$ e, O1 s, n temp = 0 6 j4 f( U4 _2 i5 L& b2 O while index<len(seq): 7 @. A M3 d2 b9 e$ s7 n """ 先移动到下一个位置 """ " v3 I( K5 Q7 F! l# X nextP = seq[index] " c0 l# i, g5 K( q( P3 o8 ~$ T t = tm[currP][nextP]2 E8 e3 ?' R' {+ l4 ]
total += t 7 h c+ q5 Z6 h9 P. V8 M6 M+ n$ x update(state,t) L1 x; m) D( ]3 ~0 ?, A
if Type[nextP]==0: # 如果下一个位置是第一道工作点 & R8 c1 r5 P8 U) `3 `( R0 k if rgv==1: # 然而载着半成品 ) z8 i+ j8 G6 z seq.pop(index) # 去掉这个元素并中止当次循环进入下一个循环% n) W9 ]8 @4 O) Q5 c) i% ~
continue ; o% K/ |, T$ \, J; P+ E% E1 r! T
if isEmpty[nextP]: # 如果下一个位置是空的" y R6 m! b3 W( U
t = cncT[nextP] % R" \; w. a% p& S total += t0 x. ^, b6 ? E/ s
update(state,t). f! n2 i' k7 P9 i
state[nextP] = T1 # 更新当前的CNC状态 + z3 {/ j; }3 `( U isEmpty[nextP] = 0 # 就不空闲了0 L* X: c" `3 v. M9 w( n7 e& d2 }5 E
else: # 如果没有空闲 ! g; r2 _/ S- f if state[nextP] > 0: # 如果还在工作就等待结束6 E5 ~6 u# b8 s8 T3 e( c/ k$ \) ]8 s
t = state[nextP] & u0 R- H2 J2 z- U total += t " t4 N2 o1 F2 g& e& g update(state,t)& _4 w5 ~2 y; _* D3 x
t = cncT[nextP] # 完成一次上下料 - B" E; e" P/ b; O" f0 C! o total += t1 ], u0 @8 W. R; R
update(state,t)3 q& v( x% V' P* X) v
state[nextP] = T1 ) [8 q5 M2 d4 C+ b: W5 `. d4 s% L& u" g rgv = 1 . b7 ^& u5 T) t1 v" m' L; X" o else: # 如果下一个位置是第二道工作点 - }$ H! H6 N+ z q4 l if rgv==0: # 如果是个空车& B: q S' M& L
seq.pop(index) # 删除当前节点 1 ]: G8 j% b# B# m w0 ?; { continue% ^8 J6 q- A# X# t, N
if isEmpty[nextP]: # 如果下一个位置是空的 ! Y8 ]; a3 w6 E/ E" ^ t = cncT[nextP] / q% I! ^( ~! c( t/ r total += t 2 X0 v& i# u" ? M3 }9 B! U update(state,t) ) `( a0 `4 G8 Y! ^: l state[nextP] = T2 6 A( R/ j5 h$ @% N isEmpty[nextP] = 0 7 s L3 `1 `7 V4 {% l& U& f- W
else: # 如果没有空闲 & F: }" l! [* T4 O# ?4 H2 j1 J& e7 s- q if state[nextP] > 0: # 如果还在工作就等待结束 4 f/ t, J9 h! s t = state[nextP]0 K/ R5 n3 f, S, [) P) c; S7 U" O
total += t i# R: C: N$ Z& ^+ }( {1 E$ [- r7 ?, g update(state,t)% Y- V* C, G2 y4 B4 u) n
t = cncT[nextP]+Tc & H3 V, b8 ?. k$ ^ total += t8 M1 |" p+ b- [' W1 V( g
update(state,t) 9 ~7 {+ ?" s4 P( @2 d$ k state[nextP] = T2 ; d' x! ], {+ Y rgv = 0 0 [) {' e" I. r- K currP = nextP 3 ^7 T* Q# L, U" f temp = total ; P* q9 ]5 P6 p+ P, y" D3 ~6 j. B index += 1 2 @: G+ _8 R1 d: w
total += tm[currP][Type.index(0)] # 最后归零 & `6 w1 r* e- ^, E return rgv,currP,total # H9 J q3 \$ m p3 O9 v- |3 g: U( x/ D6 ]1 i; l
def init_prob(sample,state,isEmpty,rgv,currP,total): # 计算所有sample的7 e9 }: |0 a: t8 L' A" e. ~
prob = []: I: g3 A) _; j7 S
for seq in sample: : M- e3 p I K t = time_calc(seq,state[:],isEmpty[:],rgv,currP,total)[-1] ) _9 G A( P' h x* x- z prob.append(t) % @0 j7 r' j4 w) q' D. }6 T: C maxi = max(prob)9 S4 s+ r0 T6 w% U* E5 q
prob = [maxi-prob+1 for i in range(N)]$ b; Z0 C+ s: V2 J/ L
temp = 0" _7 A7 ]; v: ~ e$ N( E: l
for p in prob:: L8 X3 N7 M G' `0 {3 j! ~
temp += p3 N0 r- Q u9 H
prob = [prob/temp for i in range(N)] 9 N2 C; K9 H* p for i in range(1,len(prob)): ! g1 V. N4 c1 ] prob += prob[i-1]4 ~5 P1 y3 v7 n+ t
prob[-1] = 1 # 精度有时候很出问题 # ]2 t* T2 z! V return prob0 L# A8 X9 I f5 U
8 r8 Z1 T+ F! edef minT_calc(sample,state,isEmpty,rgv,currP,total): ; a+ C% S/ w o4 U0 T, H$ K minT = time_calc(sample[0],state[:],isEmpty[:],rgv,currP,total)[-1]$ {9 I* G3 W, f& a$ I# ~/ M" R
index = 0* }% h; j6 {0 w& O( U
for i in range(1,len(sample)): 0 V; y# L+ }$ [) q6 @ t = time_calc(sample,state[:],isEmpty[:],rgv,currP,total)[-1]/ w5 i2 m6 m8 H+ m1 ]
if t < minT: " Q7 a" R Q# |; s5 n0 Y index = i 2 {( z F8 Y' [4 B minT = t - F4 v8 J, U, N7 }% a% h, k return minT,index& F9 l! N: y" g: `0 @
( n( c0 O1 `" p+ w$ \$ _8 y
def init(): # 初始化种群(按照第二道工序,第一道工序,第二道工序,第一道工序顺序排列即可) $ D) e3 l& Q+ e0 H2 t+ K& T' O sample = []; |$ U( m# v# X# Z# r* q3 v
refer0 = [] 3 d- T# Q! D; m1 k3 @* c( o refer1 = [] & H2 c2 i8 e; A8 i9 K a8 B for i in range(8):4 m( n$ U1 N' g# x8 _8 R
if Type==0:. |% S2 a# p! r
refer0.append(i) 5 \! ~8 d) V) n* n else:. y& A4 I8 `6 K8 p' R
refer1.append(i) , Y2 i8 {0 T# C7 |- b7 N for i in range(N):1 t* Y$ P# `8 X, B8 N" U. q
sample.append([]) # ^4 M7 t' b% X- S for j in range(L): 5 E, H1 Y" x: k if j%2==0:! q. ~+ k0 v5 C. `" j# a
sample[-1].append(refer1[random.randint(0,len(refer1)-1)]) 8 W( X" {4 o" @ else: . k# y [/ c X, [* \& l5 e sample[-1].append(refer0[random.randint(0,len(refer0)-1)]) Y8 A) N) H$ [, d6 l! Z" R
return sample- a- z5 `/ l) z9 b1 i+ v
! z' z1 j7 Z3 m, n9 o, C0 rdef select(sample,prob): # 选择算子 - U( c7 l/ D1 b/ c* u sampleEX = [] e& Q4 H7 ]- R& O8 F' Q( i0 X for i in range(N): # 取出N个样本 ! y1 F. j9 S, @0 M- ` rand = random.random()" c* k0 w0 u6 _9 w
for j in range(len(prob)): 5 u U+ Q+ X9 _8 T if rand<=prob[j]:3 C1 @& c+ g9 A. V0 i4 E! Y; C* X
sampleEX.append(sample[j]) 6 D* c; j2 v- |4 R! v4 i8 T; Q break & ?9 c, i3 f' q5 S0 G8 ] \ return sampleEX& j# ~5 w$ H- m, a+ a: W" U4 s; D% y
2 {$ R u( D6 |' O# H& ]def cross(sample,i): # 交叉算子+ @; l& I1 G: M5 z. L7 L
for i in range(len(sample)-1): 0 u/ ~9 n9 l4 P/ } for j in range(i,len(sample)):1 B5 p" R3 n" {, I2 m$ x
rand = random.random()# N6 X8 W2 i7 j8 Y/ @2 [' x
if rand<=croP*(e**i): # 执行交叉 / G, j0 \7 x* W loc = random.randint(0,L-croL-1) 1 F8 p/ u2 p7 H4 ?1 t6 v5 C temp1 = sample[loc:loc+croL] 4 p n8 J8 N/ P. ` temp2 = sample[j][loc:loc+croL]! M% k/ Z# A2 g
for k in range(loc,loc+croL):' P2 e' z. B$ i
sample[k] = temp2[k-loc]) ?- S, L0 S9 Q1 Q, ?/ f
sample[j][k] = temp1[k-loc] ; e9 f# \* F7 P6 \2 V- s, g return sample2 q' u; `. f/ y% G8 W
* U* Z L" x' O% j {9 p4 _+ idef variance(sample,i): # 变异算子 - J8 c0 A8 ~3 K" L
for i in range(len(sample)): ' l; A; H- g: ^, G2 @4 c rand = random.random()" ?/ ^: y3 C! T! P9 y
if rand<varP*(e**i): 9 A. Q4 i! Q+ G3 x0 { rand1 = random.randint(0,L-1) 7 B2 z1 w: A1 f randTemp = random.randint(0,int(L/2)-1)0 k2 F/ u+ x% k) u* a
rand2 = 2*randTemp if rand1%2==0 else 2*randTemp+1 8 D5 h0 V# C) T- A/ z temp = sample[rand1]5 }6 T6 X7 Y8 W8 u$ Q. K' } m& l
sample[rand1] = sample[rand2] : u- o' u" [) j* e) N' ` sample[rand2] = temp 4 }* @9 B' U6 ]8 q' q! |4 O return sample4 | K# J. j( l1 Q3 o* q0 c3 W
# Z5 S8 _ _2 o; @6 W
if __name__ == "__main__": 4 F; x6 p; y1 I- ~ state,isEmpty,rgv,currP,total,seq = init_first_round() ) z& p; P! m" d4 X/ K print(state,isEmpty,rgv,currP,total) 9 Q4 ]& I7 F0 Y! p% \ sample = init()8 n# L" c3 P. }
mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) 2 L5 f$ a2 W2 m+ R' Z" r7 ~ best = sample[index][:]. x# F; ]% y% ~/ X2 E
for i in range(100000): & o2 l9 V+ X2 d! s, E% I# \4 k f = open("GA.txt","a") , F) \/ Y' n6 G0 P" l9 {( q tmin = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)[0]3 `1 G* M' K+ b" e! L
f.write("{}\t{}\n".format(i,tmin))( P2 D0 @$ C! S
print(i,"\t",tmin,end="\t")( Y* y0 A- a. Q' ]3 L
prob = init_prob(sample,state[:],isEmpty[:],rgv,currP,total). R- a! @: M8 ^
sample = select(sample,prob) ( ?7 |& d* u9 g H; [" A sample = cross(sample,i)9 k1 a! _$ f. g9 W v
sample = variance(sample,i)+ [0 v1 k {7 l/ x) y" [
mi,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) ) `: Y) S9 g# G) [( o if mi>mini and random.random()<e**i: # 精英保留策略! [* `" g) p, g" S: q
rand = random.randint(0,N-1) / I# }2 @5 |7 M; _ sample[rand] = best[:] , i! [2 f7 K; H( v9 ` mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) 9 Y! X6 U7 E. q, H( ?2 Z: x2 x. ] best = sample[index][:]% a/ l$ ]- H, Y: |+ `4 ]
print(best) 1 B7 Q9 e% B' O3 F' _ f.close()3 S3 e! n0 N: W. v; [. J
print(sample) 2 B, Y+ Z, S% I( G3 s4 g+ [遗传算法这条路被堵死后我一度陷入俗套,用最直接的贪心搞了一阵子,觉得用贪心算法(即考虑下一步的最优策略)实在是对不起这种比赛。然后我就变得——更贪心一点了。% S/ J9 G) c( j% |& D& U
3 V n9 k' c0 f我试图去寻找接下来K步最优的策略,然后走一步。K=1时算法退化为贪心算法,最终我们设置为K=4(当K>=8时算法速度已经相当缓慢,而4~7的结果大致相同,且K=4的速度基本可以做到2秒内得到结果)。% ?, C( w0 U+ L7 x7 Z( ?
8 C7 w @5 e' e
值得注意的是我假设RGV在两道工序下只能由第一道工序的CNC到第二道工序的CNC(忽略清洗时间情况下),然后回到第一道工序的CNC,这样往复移动(这里我不说明为什么一定要这样,但是我认为确实应该是这样)。在这个规律的引导下我大大减缩了代码量以及计算复杂度。/ q# G5 Z$ C7 V+ I( c+ U+ i4 Y
6 I6 l" }1 N) b- c+ u) x# 第3组 $ K$ {2 @" I7 t0 E: _2 k% n- H7 o0 p. a1 J- g
"""4 N! r# {. t# }# V0 [- a. l7 C( q' F
d1 = 18 7 l3 u, k6 B- A9 p8 y }4 fd2 = 32% M4 l) y* U' K1 n$ W, {
d3 = 460 {- `0 D+ q- d8 A2 t% x
T1 = 4555 b" l7 \1 _* ~: b6 r' ~
T2 = 182! V3 R" c% t& J- A
To = 27- I/ @/ l( G" w! j) q
Te = 32& C( e( M4 f$ i. P1 |( F8 ^3 u
Tc = 25 $ W) \2 D2 [6 A3 {) ["""/ w {+ R2 J4 |8 y9 E
# O9 b* w% G( V6 v* x
cncT = [To,Te,To,Te,To,Te,To,Te]$ {% U+ \* { @8 ^; b
tm = [5 B2 V# N {) h
[0,0,d1,d1,d2,d2,d3,d3],1 u D: N/ u' R$ z
[0,0,d1,d1,d2,d2,d3,d3], 9 ]7 u0 \ L! D4 T- C6 [& R: v [d1,d1,0,0,d1,d1,d2,d2],+ u+ a$ _% O/ N# e5 ]" W" v; c
[d1,d1,0,0,d1,d1,d2,d2],) W( _" Y, F, z5 w- c5 ?5 Z
[d2,d2,d1,d1,0,0,d1,d1],1 r! ]" k1 N# K& ]5 N: M
[d2,d2,d1,d1,0,0,d1,d1],9 U9 `* F% \& K" `( A& y6 d' q
[d3,d3,d2,d2,d1,d1,0,0]," t2 x I" z! R h/ i
[d3,d3,d2,d2,d1,d1,0,0],. e7 [/ f) i, S" x! Y# K
]0 i, D3 W$ W, a# j6 @$ I
Type = [0,1,0,1,1,1,0,1] # CNC刀具分类 6 p: j. X9 Y$ O4 U! F( ^. ^; E8 z, _+ ]- P
A = [] # 储存第一道工序的CNC编号 . r8 E' [# P0 N" p& r, MB = [] # 储存第二道工序的CNC编号 & [4 n" b( S) b5 ]) ofor i in range(len(Type)): 8 \2 H, S: T( C" c4 a- L' |# E. V if Type:! A% |- M3 T1 C* A9 |
B.append(i) - ^. p, }! H ]* s5 A else: . v8 h9 z) j& J1 z& q- @3 O, V; T A.append(i) 3 Z+ [" M j; ` 5 @5 |& q: m" l/ @; rdef init_first_round(): # 第一圈初始化(默认把所有第一道CNC按顺序加满再回到当前位置全部加满)9 `( @2 A. y: c0 V" n' n. n, T
state = [0 for i in range(8)] # 记录CNC状态(还剩多少秒结束,0表示空闲) - [' R4 m5 f, Q" N/ E isEmpty = [1 for i in range(8)] # CNC是否为空$ e% p7 A1 C9 u0 d: H1 e# b6 y( T* l
log = [0 for i in range(8)] # 记录每台CNC正在加工第几件物料0 T% t$ X l! ~& ]2 P; I
count1 = 0 1 Q c; L6 r7 i5 W7 O9 q) e+ [% T rgv = 0 # rgv状态(0表示空车,1表示载着半成品) R& K- h/ S; ?1 r z& c+ v# S currP = 01 v: |1 w3 e, R6 Z
total = 0( B" X+ k. Z/ s2 j8 m$ y7 c
seq = [] . V; Y% o+ S8 |; a( I flag = False7 \9 }0 s, f7 Z J. Q8 n
for i in range(len(Type)): 0 V- q: I# P/ d) b2 [/ v, L if Type==0:! [/ l1 a% n2 P1 x
seq.append(i) 6 X8 R! R3 l5 k0 @$ C" V0 R$ ^4 J t: {6 J flag = True v6 n2 l: Q9 v" f5 s! j currP = seq[0] 0 ~$ g' k+ `, p1 P$ \% p/ \ seq.append(currP) y. }3 n* r1 Y! u4 \) i. Z) M count1,rgv,currP,total = simulate(seq,state,isEmpty,log,count1,rgv,currP,total)0 ]# f) v* s" J# A# b% L
return state,isEmpty,log,count1,rgv,currP,total,seq " z7 s/ e/ J: { b2 I. T r 0 O% t# c6 D# l, [: Kdef update(state,t): ; t8 Z" d' ]7 ]3 @ for i in range(len(state)):- c# U' Z% f+ P: r4 ^2 D, b4 l0 n- `7 x
if state < t: + _8 J7 G6 X1 p) v+ |/ Z state = 01 }! x' m+ o' k2 W+ X4 X# k
else: , m5 l9 [" p: f: g; } state -= t6 L- R9 Y2 U/ x
. i5 J+ G# i& g% L' Ldef simulate(seq,state,isEmpty,log,count1,rgv,currP,total,fpath="log.txt"): # 给定了一个序列模拟它的过程以及返回结果(主要用于模拟并记录) 6 s! k- C4 j9 h7 ~; L5 N7 v" m index = 0! v: o) x0 C( [* z( s
temp = 0# ?8 N* C* n0 n! H3 d/ _
pro1 = {} # 第一道工序的上下料开始时间 , J7 b" y+ B y* Q7 A+ n pro2 = {} # 第二道工序的上下料开始时间 % H, u0 C0 n( G f = open(fpath,"a")6 k' _/ Y3 ^8 B! @1 T: U
while index<len(seq):0 o+ u: s! w: m
print(isEmpty) ! D% p2 J8 Z p: b7 i% ~ nextP = seq[index] " |8 E9 M4 n6 Z$ r t = tm[currP][nextP]& i2 z) l5 F; {- N: d: |
total += t 0 N3 K# M/ y& f. R% L update(state,t) " m" t* P) I' t+ V! z5 a if Type[nextP]==0: # 如果下一个位置是第一道工作点- \! W' Z9 i* b& B7 L
count1 += 1 $ N2 h: s8 C+ k8 Y; q, @; J- p7 V if isEmpty[nextP]: # 如果下一个位置是空的 ! I/ q# \4 j# @. [ f.write("第{}个物料的工序一上料开始时间为{}\tCNC编号为{}号\n".format(count1,total,nextP+1))8 w6 {8 n& d" U/ V: C; y
t = cncT[nextP]4 ]+ i3 g. l/ ~ E
total += t. m+ G5 s% U& l7 P# W9 @: W
update(state,t)* p0 _; K% T- ?* A
state[nextP] = T1 # 更新当前的CNC状态1 o d" e8 e- B% h( F
isEmpty[nextP] = 0 # 就不空闲了 9 Z, j _, D& D else: # 如果没有空闲 7 R( w" Q/ D$ j( g( A& W2 r if state[nextP] > 0: # 如果还在工作就等待结束9 b+ E9 z5 F1 \( ?5 i
t = state[nextP] " z% c4 X3 J8 }3 g, b total += t . v6 S% _" S+ K* }& I" ? L update(state,t)) @7 u+ ^ i" A- h0 f {6 Z+ o
f.write("第{}个物料的工序一下料开始时间为{}\tCNC编号为{}号\n".format(log[nextP],total,nextP+1))' K: v4 q0 N- T$ E4 S, A/ {
f.write("第{}个物料的工序一上料开始时间为{}\tCNC编号为{}号\n".format(count1,total,nextP+1)) 7 j4 [3 m$ m( _& q4 v7 W t = cncT[nextP] # 完成一次上下料! [9 E0 I8 V5 k
total += t 6 [0 ^. V( f3 o. x% K update(state,t) , {& P5 G- ]0 i( ~! u state[nextP] = T1' u3 h, ?' n. X7 a9 |
rgv = log[nextP] - {" T: b% z9 h; P$ p log[nextP] = count1 ! h8 O' B1 N% z) K+ K/ B7 o else: # 如果下一个位置是第二道工作点! a' `2 J3 X; J Z6 n) z1 t, w
if isEmpty[nextP]: # 如果下一个位置是空的9 x) c) T$ T) m6 \
f.write("第{}个物料的工序二上料开始时间为{}\tCNC编号为{}号\n".format(rgv,total,nextP+1))) Z% l( D7 L# D# P
t = cncT[nextP]5 m) s( q9 ?, ?
total += t$ D: s# I$ w0 d
update(state,t) 6 E. P' R0 E9 j7 F! o state[nextP] = T2 - t: s. w# A% T, e+ ^! g# U isEmpty[nextP] = 0 + k& V; C, y9 m6 ]1 h else: # 如果没有空闲 5 w. {# G4 M8 X( ] f.write("第{}个物料的工序二下料开始时间为{}\tCNC编号为{}号\n".format(log[nextP],total,nextP+1)) , u; r3 y; {1 \$ @: G f.write("第{}个物料的工序二上料开始时间为{}\tCNC编号为{}号\n".format(rgv,total,nextP+1)) . z) G+ L, l( X! g4 g8 h7 H if state[nextP] > 0: # 如果还在工作就等待结束 % g g/ E( H+ I: i8 N1 P8 F t = state[nextP] * `: t! A @8 a* H; D( i total += t4 [ y0 j7 @" t+ T6 M
update(state,t) ! U2 s4 t1 A! u/ Y# ]- y9 | t = cncT[nextP]+Tc & Y- S6 B4 v9 K- H! f/ s& l+ r total += t ! B" o/ X. G* p! H5 q update(state,t) 5 l9 _: H( _" Y( E! n! N state[nextP] = T2$ _* U* m- T+ i9 ~, t, ]
log[nextP] = rgv2 S% [' A$ A6 ?; m( X0 v+ t
rgv = 0 ; x, ~% A" t7 A* T currP = nextP ; n0 C6 } c. W7 }; @5 Z* x temp = total 4 o! n$ M' T) u* Q8 w! A index += 1 9 _% Z2 p* q- c# E+ `
f.close() 8 N0 M7 f0 h% w0 P total += tm[currP][Type.index(0)] # 最后归到起始点/ K# a8 Z: `6 G2 N" V0 |
return count1,rgv,currP,total * l7 E8 R% ^+ i+ s# n. {) I5 I3 e8 z; w, g, q5 j3 Y0 H
def time_calc(seq,state,isEmpty,rgv,currP,total): # 主要用于记录时间 : }1 |' g2 Y* B5 X index = 0 / ]0 M1 r' X v: ^! l; x+ r temp = 08 |5 x) \2 L- d# g9 `3 B7 Z3 ]
while index<len(seq):& b' k- D$ {% z" z( q
nextP = seq[index] ; D, \: u& Z% N" c, ]6 {% ~% a/ Z9 ] t = tm[currP][nextP] 8 k( F$ l4 H& }# S8 N& n total += t 3 @. a8 ~" h% b4 N* y3 ` update(state,t) $ f' T: { b6 m* h if Type[nextP]==0: # 如果下一个位置是第一道工作点. d$ ^! X; Z+ ]: H
if rgv==1: # 然而载着半成品3 p0 b; V( n9 t
seq.pop(index) # 去掉这个元素并中止当次循环进入下一个循环 / \0 E* o) K# N; V continue ! d- j m- ~2 I: z9 w6 R! \2 o if isEmpty[nextP]: # 如果下一个位置是空的8 Q/ S; c9 \; V, ^
t = cncT[nextP] # E$ T5 W! t+ k2 q$ `2 Z total += t( L" k0 H: D( |4 K/ Z2 `
update(state,t) & I) O% _4 W4 {, c state[nextP] = T1 # 更新当前的CNC状态+ Z8 d) ?' f/ ~) q: @( U
isEmpty[nextP] = 0 # 就不空闲了 " o+ Z% a. j1 L; f' y# P else: # 如果没有空闲" W2 Y. L7 o0 _) L& L
if state[nextP] > 0: # 如果还在工作就等待结束 # l+ x7 @8 J, x t = state[nextP] 2 ^. Z" [) E* @; `# Q total += t% n4 h! J; A4 h& o- [
update(state,t): k `4 Q* R; B3 Q2 e3 Y# s1 B# q
t = cncT[nextP] # 完成一次上下料: J: \$ m+ A9 x0 U# [7 `& p* n
total += t / {3 C) S# G3 R! l2 n% I update(state,t)* V& J' A0 u- j5 d9 e$ y
state[nextP] = T1. F5 f; ?& L+ T
rgv = 17 G8 o" x5 B7 I& O; C
else: # 如果下一个位置是第二道工作点 ( {% w3 c' {$ u1 |) j/ g if rgv==0: # 如果是个空车 , X2 B% r2 Z4 g, D( B seq.pop(index) # 删除当前节点7 ?3 |- Y. ]4 j2 K; V; A
continue " {" [. W, y( m2 e/ J7 c if isEmpty[nextP]: # 如果下一个位置是空的 7 M7 y+ g! @% l t = cncT[nextP] + c* R; X/ b {5 j+ s7 U) _ total += t ( X3 ~! h/ K% X; p0 _ update(state,t)8 h i+ p; f) `8 g/ b
state[nextP] = T2% a. q" [- A! X! O# g/ J* `
isEmpty[nextP] = 0 # D T. y- Y% L& E else: # 如果没有空闲! D# F8 q' R' w, u
if state[nextP] > 0: # 如果还在工作就等待结束 3 S+ a1 @* r% F$ |! Z& ~7 T9 t t = state[nextP] 4 b. Y6 Q$ h3 T" w3 v' T total += t 6 V0 B1 E; L% ?( r7 L2 s0 b update(state,t) 2 K9 w: J1 v A8 z' r8 Q& E8 b t = cncT[nextP]+Tc( U! @* {; d" ]0 q8 K l" r
total += t % a/ r2 X* _ u' G2 W; o4 o update(state,t)) r4 Z& I# `- g
state[nextP] = T24 m8 K1 T( N5 ~( J& q
rgv = 0& [$ R- Q3 l% s" [/ } h; d" p
currP = nextP 1 w" n2 u. \5 o8 i8 I% \/ U- K; f temp = total 7 |) B* ]# f& {: E9 q index += 1 Y/ ^# Q. C3 m P3 n
return rgv,currP,total! C7 o$ w& v5 G0 x& v5 f
7 N, ^. c# E- h% Idef forward1(state,isEmpty,currP): # 一步最优 7 T- n! s5 \3 C lists = []. \2 [) N" @0 r0 e2 Z
if currP in A:" J% J: y$ [; i& }4 w8 s7 {
rgv = 1 ) ?( ^, ~: F9 K* t9 K! `5 |) W for e1 in B: % J; D" T' T$ g4 U6 ~5 g3 L' J lists.append([e1])' A. \& _6 T+ G3 H9 o
0 @" u. p/ Q- Y+ z4 G$ D2 _- Z else: % `) z$ k# p1 O8 \; S% B rgv = 0 ; Y2 k i+ c# U" S( G for e1 in A: - R1 ^1 y* a& { lists.append([e1])* C, r; m2 D- ^3 J( N
+ A2 f8 c) t, Z6 V minV = 288005 u, P9 R* V+ }0 D% F
for i in range(len(lists)):% c( p7 _' b) O
t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]! d- q/ C; q- q8 A; D! A
if t<minV: - ?: X1 T$ \' ^9 k minV = t4 S% v" O4 l' Z) A
index = i ( a3 X, k% u$ l( [4 x' T4 j2 t return lists[index][0] 2 V* S; i% B/ X5 k6 y ! x8 S. |0 z2 x$ Rdef forward4(state,isEmpty,currP): # 四步最优# s8 o: j) N2 ]8 j# u5 b3 c1 u g1 k
lists = []- R# E- g3 p5 E2 G
""" 遍历所有的可能性 """ ) R5 B! H' ]/ J1 b if currP in A: # 如果当前在第二道工序CNC的位置; a4 }9 T+ W4 l
rgv = 1 . [" s S3 E c% A+ F0 H Q8 s5 f0 [ for e1 in B: 3 }$ o! n. p$ V for e2 in A:. Y9 H( R8 r4 h0 Z$ F9 E
for e3 in B:* Y; @$ A2 k3 a; Q* I$ o
for e4 in A: 2 f4 _. _8 p& m6 l" O# n lists.append([e1,e2,e3,e4])+ y- L& q4 r- i/ k. q( s& Q
else: Q) {% _! q" y" i rgv = 0& e4 }! a/ N q- [6 P+ X0 N
for e1 in A:; s( z6 y0 L7 ~ T( t* V8 W
for e2 in B: 1 b# M' P/ q! n. {9 |# x4 a7 T+ O/ e for e3 in A: , L. W+ z$ G5 m4 f5 } for e4 in B:# P' V [; J T. P% B. G$ F! r
lists.append([e1,e2,e3,e4]) 7 ~" Z2 G: e9 W Y$ s9 b7 G minV = 28800 7 S; f) C" d! f: f: e' @ for i in range(len(lists)): & f* Y+ b) d( h; D' @) s- R( j t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1] v! c/ p. {. K: T if t<minV:7 ]( M1 ~3 W& m' h7 N8 M
minV = t u/ o7 T) v! Q0 I# E7 e9 M" Q index = i6 z6 k5 a) E( y
return lists[index][0] # 给定下一步的4步计算最优" `+ n, A0 Y: W! J9 l
* n# H1 i- x8 a3 b9 C& Ydef forward5(state,isEmpty,currP): # 五步最优, Z- E2 ~" T, J+ K/ x2 a+ S8 N n3 c
lists = []' f: e# w/ V% g* O5 d
""" 遍历所有的可能性 """% o. C7 ~0 s' ?1 U g0 ?, b
if currP in A: # 如果当前在第二道工序CNC的位置 4 }/ \* Q4 e/ b: |7 s rgv = 11 R) \! P7 z# h) U
for e1 in B: - s; q$ z1 j1 a" [! T ^6 ? for e2 in A: ; X0 b/ ~0 ]$ I" {5 {3 P p( h5 ] for e3 in B: f/ c: T+ T' H& K a( C for e4 in A: 3 _1 T& `5 Z3 F5 }; j% |# K for e5 in B: 6 u3 }- C2 d! g7 l lists.append([e1,e2,e3,e4,e5])6 Y# ?# W* [3 {* o1 h+ r1 q
else: ' [ ?9 K7 d% P% k S2 Y5 h rgv = 0 ( {) ]7 F+ v, j. Q. M for e1 in A: 3 p* a6 z, d0 O for e2 in B:$ O5 ^9 v- Y6 x* L; J
for e3 in A:! u1 o. p( r, I% W3 L4 m& ]
for e4 in B: & R' |4 _4 t0 |8 R7 G5 T6 ~ for e5 in A: ~( H: Y+ _0 D! M lists.append([e1,e2,e3,e4,e5])" U- ^& d9 Y7 n5 f
minV = 288004 }9 E' a) C# V7 c4 O$ N! T5 N
for i in range(len(lists)): " g# q1 m0 I. }1 b3 V0 z0 @8 a6 k t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]: z, i0 N) |$ W9 N6 a1 Q
if t<minV: ; S8 S4 i% |, e4 k) ^ minV = t 3 o# S0 U- _+ b' B' ~ index = i0 ~9 w7 n# t ?$ \
return lists[index][0] # 给定下一步的5步计算最优0 f6 j$ w5 d. Y- |
, `( ^! \/ K, z& h4 edef forward6(state,isEmpty,currP): # 六步最优 3 i* I) e: e# n1 x1 b lists = []3 K: m1 \5 {7 `. A' j* X
""" 遍历所有的可能性 """ ' a/ }. Q1 g& Q- m- n3 U if currP in A: # 如果当前在第二道工序CNC的位置0 l" U. p5 L1 J
rgv = 1 8 W. p( f" Y# | b& s) [* k for e1 in B:% q& I) I$ B; U& E" | k
for e2 in A:7 J" u7 T7 A2 u" @: H4 o2 ?" ^
for e3 in B: % }4 L# w; o* ~7 v' T4 Y for e4 in A: 8 }& j' K7 H i! H+ N* o for e5 in B:/ b$ v; C0 C; W( m$ D( ~1 B
for e6 in A:# i' r! g% y$ A0 B8 {. `
lists.append([e1,e2,e3,e4,e5,e6]) 7 T4 u. c8 O. d5 R, v; Q else: 4 a( m7 q% |- e! m0 ~; `; _/ p rgv = 0- u0 ?* K/ ^/ d4 ~! H2 |: R8 `/ p
for e1 in A:. D, d( f @8 ~
for e2 in B: , x, ?+ c& R$ t: O& O for e3 in A:1 V& i9 d0 n2 ^% T; N/ V3 H
for e4 in B: 3 @. d8 Q$ I9 E2 X* ~ for e5 in A: 2 v" ?. \2 y- @ for e6 in B: ) ?2 U! }' E; j' a lists.append([e1,e2,e3,e4,e5,e6]) 0 N+ i) n. Q9 F8 g minV = 28800, C/ Q5 ~: F% X& S
for i in range(len(lists)):# K+ Z. K3 L0 { I5 O4 N
t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1] - ^* f9 a3 Q. F+ M if t<minV:0 H: N- L5 H/ N1 F( P+ c
minV = t 0 K8 A8 n% B. a; D( i t8 @0 r. u& K index = i& Q& y3 F& t4 R! c4 ?% w
return lists[index][0] # 给定下一步的6步计算最优 6 k1 g$ E0 y+ v9 q 6 P* S% ]- s8 I( m9 j3 Cdef forward7(state,isEmpty,currP): # 七步最优 , b" W9 ?: V) {3 b. f2 ] lists = [] I9 Z) V% S0 V8 B/ ~( I, J """ 遍历所有的可能性 """ ! E7 y& A% r; R/ p; k: g V" Q s if currP in A: # 如果当前在第二道工序CNC的位置 ( b s d E1 T# S7 j rgv = 1 9 j0 S' @+ I0 `' ~# u* p for e1 in B:# z% x* l) ^2 _5 I
for e2 in A: ( O1 k/ w, Z: J$ U+ _ R for e3 in B: ! [4 E G. S; C* ^. |, }% z for e4 in A:: C+ b/ ~' @6 ~: E
for e5 in B: 4 p" ?9 s h6 o4 i for e6 in A:( D' H" w1 I* P* B: r) L: t$ V
for e7 in B: * i, O, N( G- {+ e! g' @ lists.append([e1,e2,e3,e4,e5,e6,e7])* J( D- K" r+ {: E p
else: ) y- w! g* Y' U4 E8 L8 C rgv = 08 H v/ q0 g: `8 [
for e1 in A:# H4 m3 z; p5 f+ q8 }4 F! D( @. H7 r4 b
for e2 in B: / B8 p: Q* m2 [; z9 M for e3 in A: 7 Y& z7 c2 e2 G, b5 r4 q# h5 F! B for e4 in B: 4 v. Z8 l9 X- s1 D7 ] for e5 in A: * N3 q& U( C" q' ?) j. ?6 W for e6 in B: " q+ T$ ?1 e7 U5 N3 j2 ?; ` for e7 in A:# k: }2 j4 B" f a& M& i& V
lists.append([e1,e2,e3,e4,e5,e6,e7]) ! ?% |2 N1 H5 q# H! |# I/ Z minV = 28800& ^ r7 U0 U5 P
for i in range(len(lists)): * P) {" @3 e2 l; [ t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]6 P2 `1 m+ d, i: ^
if t<minV:, T, x N6 R2 [: T7 Z5 L
minV = t$ m0 P0 N8 c1 B/ \! C! e
index = i$ q8 \, P) {2 _8 J3 X' S
return lists[index][0] # 给定下一步的7步计算最优 : [& o5 o* }9 O E5 E6 j; a {$ N) P& b% x) L) |
def forward8(state,isEmpty,currP): # 八步最优/ H# z" x/ J. M5 y7 a/ f! a
lists = [] : u. |# o$ V5 M+ s7 w0 U+ Q- V( X """ 遍历所有的可能性 """! k8 e7 d# h2 Z7 A! p3 ^
if currP in A: # 如果当前在第二道工序CNC的位置 , \! p7 P* v' n* r rgv = 1 + v p n) d/ f for e1 in B: * Z& D5 E1 J1 ~* }: G for e2 in A:* u5 P+ m5 } M% R7 L
for e3 in B: - Y( _2 G% u6 {& E! W& E; s for e4 in A: 2 C$ E/ T, Q+ l" l' ^4 ~ for e5 in B: + e2 n1 F4 e& _- j& a for e6 in A: 6 g0 ^+ i5 Y! k( G, ` for e7 in B: `9 a: l2 U: h1 c5 O8 q) H6 `: ? for e8 in A: ; D( ^' U& D6 |" C lists.append([e1,e2,e3,e4,e5,e6,e7,e8])2 F/ n& @# ?& O
else:* @9 f- y0 X1 L- V5 d* ?
rgv = 0 2 U/ O# A4 A# F: D! M for e1 in A: 0 ~' B! V) _5 a0 D5 r) J8 @9 q5 Z for e2 in B:4 z* L; q$ A K6 Y( Y9 O3 y
for e3 in A: : @9 v3 L9 W& S' b5 g3 Q for e4 in B: 9 M" X4 U _* N9 w2 q for e5 in A: & {. M) K4 u! R" E for e6 in B: % d8 v- W/ V' Z$ f2 C2 ~4 a for e7 in A:6 k' D' [+ H' h) i0 {0 E
for e8 in B:, y% \' }1 [1 d/ d4 A
lists.append([e1,e2,e3,e4,e5,e6,e7,e8]) 5 x* m3 R( o: ^9 c& H) Q minV = 28800- C: G N( D0 t3 i; d. h+ [9 }
for i in range(len(lists)): " N" E) S4 n( E6 z6 E) i t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1] * b1 A$ w8 W/ F/ S, y0 u; z if t<minV:9 V" d8 \/ H; t X3 \+ W
minV = t 8 ?/ P0 j/ F0 T2 v index = i ) P( t. D) L# C* h: ? return lists[index][0] # 给定下一步的8步计算最优 ) W9 ^. v5 d6 Z; `! x8 h1 t' q9 `2 ? 6 w* d/ ^, }% n3 R( x) Bdef greedy(state,isEmpty,rgv,currP,total): # 贪婪算法4 {7 C5 W5 e. r8 r) ~+ c7 ]
line = [] + S: F( S& S w# y+ R count = 0 7 i4 z: s, G$ W4 Y" c while True: 5 u1 x! |# \) J2 L/ }* c+ @ #nextP = forward4(state[:],isEmpty[:],currP) ; I. {, x1 ?0 _* ]1 }
nextP = forward5(state[:],isEmpty[:],currP) 6 }, d* i* O) z# @/ q
line.append(nextP)0 |1 T- r3 v; ?' y/ V
rgv,currP,t = time_calc([nextP],state,isEmpty,rgv,currP,0) : s- \- \. C0 | t" j& j$ S total += t 9 b! ?. x; m A5 b count += 18 H: C" F6 I% A7 G
if total>=28800: " K/ A5 W) R$ W& |) }4 Y" W break # G! j2 j' t3 e return line o! ]) o3 L, f4 |0 I . U% h6 b6 |, d! x$ Tif __name__ == "__main__":4 d/ d" V3 j/ O+ j, e1 f- z: m& b' i
state,isEmpty,log,count1,rgv,currP,total,seq = init_first_round() + ~3 ?9 u8 B. l print(state,isEmpty,log,count1,rgv,currP,total,seq) 4 _ J9 v( X/ R5 c* r4 k% D1 Z) J7 ] line = greedy(state[:],isEmpty[:],rgv,currP,total) 8 h; p; U* j% [( j- c' v! H3 R simulate(line,state,isEmpty,log,count1,rgv,currP,total)& b7 z5 R% A/ |+ Q' e) @
) o( |- `. J/ J0 X# ~& B
write_xlsx() " e# d; w# P! f1 r2 T0 v# R后记+ n2 ?/ a& h* q/ S
* Z+ }: I4 Z/ ^) ^, Q$ @' @
这次博客有点赶,所以质量有点差,很多点没有具体说清楚。主要最近事情比较多。本来也没想写这篇博客,但是觉得人还是要善始善终,虽然没有人来阅读,但是学习的路上还是要多做小结,另外也是万一有需要的朋友也可以给一些参考。虽然我的水平很差劲,但是我希望能够通过交流学习提高更多人包括我自己的水平。不喜勿喷! ( I( L# n- f6 h% B @! S* h; H--------------------- 8 n1 j3 p* D* c5 ^6 J& A+ Y# @+ F
! h0 A7 P4 f$ q2 Y( Q
, ^' d. L, V* d) ? G6 T: B! p" C4 A3 q& z3 ~' F6 q8 C' N9 e1 F
9 a o# f6 A) u# M. j ) l& C0 K1 m- d/ n1 I - A6 U2 V: \4 `* N6 e( @5 n ; T; J" @" |+ i+ Q% C+ @( Y* e$ P! ~8 \; a3 \5 v