|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
& _ ?7 r/ ?+ p+ _6 Z一、简介" m z/ d3 O2 z
4 T* t( D- B5 D- t+ e: E8 F8 S; k( n7 Q8 [ I, h5 Z
一、问题分析
0 V7 U/ D: M: e' A6 w$ u# f3 m9 w3 S V, z/ a2 e
如图如示,将节点编号,依次为1.2.3.4.5.6.7.8.9.10.11,由图论知识,则可写出其带权邻接矩阵为:4 s; f8 B6 J. a/ H- R6 p3 c* `
# o1 {" f$ }* u4 o% A
- 0 2 8 1 500 500 500 500 500 500 500
- 2 0 6 500 1 500 500 500 500 500 500
- 8 6 0 7 500 1 500 500 500 500 500
- 1 500 7 0 500 500 9 500 500 500 5005 A: h5 W# t& b
c5 i4 ^8 V s( f- S
/ |% c2 h a. o8 p% k
500 1 500 500 0 3 500 2 500 500 5006 l" N: J4 ]6 q9 s& G3 n8 ?
" T W; n4 s% d$ L* ^0 L: D
500 500 1 500 3 0 4 500 6 500 500" s5 z& B7 M3 u- I% A ^
+ V, l/ t& E: R2 N# m+ b E
500 500 500 9 500 4 0 500 500 1 500
4 o" K: X9 I- V+ }. d+ R. G' G5 h+ n
500 500 500 500 2 500 500 0 7 500 9
! A4 V% D7 m! _' S" H4 e# r+ t& d! Z, N+ ^+ H$ \3 h
500 500 500 500 500 6 500 7 0 1 2
, N$ s4 E+ m7 n$ S8 e( E0 c& z* R! R, j7 H. v. [& Z
500 500 500 500 500 500 1 500 1 0 4 `& w% v+ R" f( a7 r. ?
$ l' `* V* `+ d$ x
500 500 500 500 500 500 500 9 2 4 06 g/ e4 a2 H7 i, }2 Y: r
% Y- H7 u4 a5 W: e
注:为避免计算时无穷大数吃掉小数,此处为令inf=500。; O! p# B2 T7 i. O
/ \- s1 Q$ z# n% I' F
, u0 x& d4 a8 T
问题要求求出任意两点间的最短路径,Floyd算法采用的是在两点间尝试插入顶点,比较距离长短的方法。我思考后认为,用遗传算法很难找到一个可以统一表示最短路径的函数,但是可以对每一对点分别计算,然后加入for循环,可将相互之间的所有情况解出。观察本题可发现,所有节点都是可双向行走,则可只计算i到j的路径与距离,然后将矩阵按主对角线翻折即可得到全部数据。" Q! H+ b e0 T, o9 a- d' k
9 E! j7 {) {9 C, K. ]1 s. \
4 P) [! E: M& n2 h% G' |9 n. V3 q. c ^& z2 |) _, ]
二、实验原理与数学模型
& E+ t/ {) N( p j; R
; ` e% ~9 g3 Q" ]实现原理为遗传算法原理:0 z: o; N: m) B# ?
5 p( c) F3 r* m1 q: | n
按所选择的适应度函数并通过遗传中的复制、交叉及变异对个体进行筛选,使得适应度高的个体被保留下来,组成新的群体,新的群体既继承了上一代的信息,又优于上一代。这样周而复始,群体中个体适应度不断提高,直到满足一定的条件。
. a6 O; n1 A- o! J& G
% H9 i- g. _7 N( m6 k; a5 ~& i! M数学模型如下:+ p) M" W" [8 p. q+ b/ N$ c
0 c" o2 B' ~: l! \% }/ E* U
$ _, A" p8 V8 m1 K* \8 w
; r0 ^7 f' `" V5 e* v2 J/ ~4 d) F
+ `( k& e) C `7 s" D B实验具体:
/ |* c+ M, G+ G9 P; k$ G
f! g4 L$ Y5 F3 ~+ P. q第一:编码与初始化( p" r3 [! x' D" r" K
" B% Z- q7 Q6 Z$ a
因采用自然编码,且产生的编码不能重复,于是我采用了randperm函数产生不重复的随机自然数。因解题方法是使用的是计算每一对点,则我们编码时将第一个节点单独放入,合并成完整编码。; Y6 @6 ~( s) B5 U
+ ?, ]2 x8 A! K8 j( n3 G因为节点有11个,可采用一个1行11列的矩阵储存数据,同时,由于编号为数字,可直接使用数字编码表示路径的染色体。具体如下:
, Y& a) g, z; j1 R+ T5 S! s4 Y# o8 j- Y0 h
采用等长可变染色体的方式,例如由2到9的路径,染色体编码可能为(2,5,1,8,4,6,9,3,10,7,11),超过9之后的编码,用来进行算子的运算,不具备实际意义。
& W/ ~) E- w$ ^" U$ M" B; p4 \8 }1 l1 k$ l; q! F/ V
第二:计算适应度,因取最短路径值,即最小值,常用方法为C-F(x)或C/F(x)(C为一常数),此处采用前一种方式。于是,可进一步计算相对适应度。
6 |. T# z4 A! S1 ]; O2 w+ x* z: a$ X) Y! h2 i6 y7 |/ g
第三:选择与复制/ b2 T: `' v! T/ U
' Q$ E R+ N7 g& {( Z6 o采用轮盘赌算法,产生一个随机值,比较它与累计相对适应度的关系,从而选择出优良个体进入下一代。
5 m% Y& f C0 }' v ?5 b- N. W
5 c2 k6 {1 |' B) ^& e" q' T第四:交叉。
' n$ a' k4 w8 x! q% d( Q. c; l* ?* W! j: `+ i9 b# V* h% i
因编码是不重复的数字,所以采用传统的交叉方法,即上一行与下一行对位交叉,会产生无效路径,于是,采用了不同的交叉方法,具体如下:
2 J! @% B7 _2 D' R3 D5 S, y; [! ~. K% _2 j
(1)在表示路径的染色体Tx 和Ty中,随机选取两个基因座(不能为起点基因座)i和j, 即将i个基因座和第j个基因座之间的各个基因座定义为交叉域,并将交叉的内容分别记忆为temp1和temp2。
: ~6 V. K6 a" P: z3 ]6 l! K% I8 g) p) ] E; L9 I
(2)根据交叉区域中的映射关系,在个体Tx中找出所有与temp2相同的元素,在个体Ty中找出所有与temp1相同的元素,全部置为0。
% ~ c# N: R7 _. M& A
( C+ l; f/ a. s(3)将个体Tx、Ty进行循环左移,遇到0就删除,直到编码串中交叉区域的左端不再有0:然后将所有空位集中到交叉区域,而将交叉区域内原有的基因依次向后移动。因0元素可能较多,在程序实现时,我是将非零元素提出,后面再合成。: b8 E+ _7 f& f& f j5 m4 x' A
6 }5 D8 |( g1 b! p, p, H( W7 r6 y(4)将temp2插入到Tx的交叉区域,temp1插入到Ty的交叉区域。形成新的染色体。6 j. E4 e5 o/ S
" i l+ ^( G4 z第五:变异6 r: a% ~2 c$ u7 N5 J
) E4 B7 w' M3 ^, w; M6 o( z染色体编码为从1到11的无重复编码,所以不能采用一般的生成一个随机数替代的办法。此处采用交换变异法。即随机产生两个数,交换两个节点的顺序。
W _0 [/ b8 R* `: S1 T1 u5 @9 A$ b. p$ ?" u% |
9 n, c4 t$ l6 W" F$ {; ]; `. X) h0 h! a7 `9 Z
二、源代码- C e* l2 J5 s/ B& {1 I
- clc;clear;
- %初始化参数
- %注:popsize=200,MaxGeneration=100,约跑2分钟。若不要求太精确,可减少循环次数。
- pointnumber=11; %节点个数
- Popsize=200; %种群规模,只能取偶数(因67行的循环)
- MaxGeneration=100; %最大代数
- Pc=0.8;Pm=0.3; %交叉概率和变异概率
- A=[0 2 8 1 50 50 50 50 50 50 50
- 2 0 6 50 1 50 50 50 50 50 50
- 8 6 0 7 50 1 50 50 50 50 50
- 1 50 7 0 50 50 9 50 50 50 50
- 50 1 50 50 0 3 50 2 50 50 50
- 50 50 1 50 3 0 4 50 6 50 50
- 50 50 50 9 50 4 0 50 50 1 50
- 50 50 50 50 2 50 50 0 7 50 9
- 50 50 50 50 50 6 50 7 0 1 2
- 50 50 50 50 50 50 1 50 1 0 4
- 50 50 50 50 50 50 50 9 2 4 0]; %带权邻接矩阵。
- A(A==50)=500; %取值50过小而修正为500;
- Bestindividual=zeros(MaxGeneration,1);
- outdistance=zeros(11,11);
- outpath=cell(11,11); %用于存放11个点相互之间的最短路径
- %****** 生成初始种群 ******
- for a=1:pointnumber %起点的编号
- %a=1;
- tempvary=[1 2 3 4 5 6 7 8 9 10 11];
- tempvary(a)=[]; %暂时剔除起点
- tempmatrix=a*ones(Popsize,1); %将起点单独放一矩阵
- path=zeros(Popsize,pointnumber-1); %声明矩阵大小,避免减慢速度
- for i=1:Popsize
- temprand=randperm(pointnumber-1);
- path(i,:)=tempvary(temprand(1:end)); %生成一系列剔除起点的随机路线
- end
- path=[tempmatrix path]; %合成包括起点的完整路线
- [row,col]=size(path);
- for b=a:pointnumber %终点的编号
- %b=10;
- for k=1:1:MaxGeneration
- for i=1:row
- position2=find(path(i,:)==b); %找出终点在路线中的位置
- pathlong(i)=0;
- for j=1:position2-1
- pathlong(i)=pathlong(i)+A(path(i,j),path(i,j+1));
- end
- end
- %计算适应度
- Fitness=length(A)*max(max(A))-pathlong; %因要求最小值,采且常数减函数值构造适应度
- Fitness=Fitness./sum(Fitness);
- %****** Step 1 : 选择最优个体 ******
- Bestindividual(k)=min(pathlong);
- [OrdeRFi,Indexfi]=sort(Fitness); %按照适应度大小排序
- Bestfi=Orderfi(Popsize); %Oderfi中最后一个即是最大的适应度
- BestS=path(Indexfi(Popsize),:); %记录每一代中最优个体的路线
- %****** Step 2 : 选择与复制操作******
- temppath=path;
- roulette=cumsum(Fitness);
- for i=1:Popsize
- tempP=rand(1);
- for j=1:length(roulette)
- if tempP<roulette(j)
- break;
- end
- end
- path(i,:)=temppath(j,:);
- end
- %************ Step 3 : 交叉操作 ************
- temppath2=path;
- for i=1:2:row
- tempP2=rand(1);
- if(tempP2<rand(1))
- temPm2=fix((rand(1)+0.2)*10); %因起点基因不能改变
- temPm3=fix((rand(1)+0.2)*10); %随机取出两个位置为2到11基因座
- temPm4=min(temPm2,temPm3);
- temPm5=max(temPm2,temPm3);
- temp1=path(i,temPm4:temPm5); %将两点之间的基因储存,方便交叉
- temp2=path(i+1,temPm4:temPm5);
- [c d]=find(ismember(path(i,:),temp2));
- path(i,d)=0; %找出i行在i+1行取出区域中的数,置为0
- [e f]=find(ismember(path(i+1,:),temp1));
- path(i+1,f)=0; %找出i+1行在i行取出区域中的数,置为0
- [g h]=find(path(i,:)~=0);
- v1=path(i,h); %取出i行的非零元素,成一向量
- [l m]=find(path(i+1,:)~=0);
- v2=path(i+1,m); %取出i+1行的非零元素,成一向量
- path(i,:)=[v1(1:temPm4-1) temp2 v1(temPm4-1+size(temp1):end)];
- path(i+1,:)=[v2(1:temPm4-1) temp1 v2(temPm4-1+size(temp2):end)]; %基因交叉
- end
- end
- path(Popsize,:)=BestS;
- %************ Step 4: 变异操作 **************
- for i=1:Popsize
- tempPm=rand(1);
- if(tempPm< Pm)
- temPm6=fix((rand(1)+0.2)*10);
- temPm7=fix((rand(1)+0.2)*10); %产生两个用于交换的随机数
- tempvessel=path(i,temPm6); %交换前用一临时容器存放数据
- path(i,temPm6)=path(i,temPm7);
- path(i,temPm7)=tempvessel; %变异交换
- end
- end
- path(Popsize,:)=BestS;
- end
- [aa bb]=find(BestS==b); %找出终点
- Bestpath=BestS(1:bb); %剔除后面无用的点,留下实际路线
- outdistance(a,b)=Bestindividual(k); %将最短距离写入矩阵
- outpath{a,b}=Bestpath; %写入路径,因数据类型为矩阵,所以采用元胞数组储存
- end
- end
- for i=1:pointnumber
- for j=1:i
- outdistance(i,j)=outdistance(j,i); %实现距离的对称
- outpath{i,j}=fliplr(outpath{j,i}); %实现路径的对称与翻转
- end
- end
- %*************** 结果输出 *****************
- outdistance
- celldisp(outpath)
- %xlswrite('tempdata.xls', outpath) %存入excel中进行操作
' m' k4 V* B6 W" }. _
' K0 Y: B7 l9 N& S. p
$ L, u7 x+ a% a9 O三、运行结果
3 `' b% |" u$ C. P6 H. F$ B, y) ?$ k6 _! n3 Z+ l
距离矩阵:a(i,j) i表示起点,j表示终点。4 K z; D/ r8 g4 ]( {
+ e" F7 H3 F4 d0 Eoutdistance =& Y9 Q2 e2 G5 x- U
3 s+ q4 c% D- x: f2 Y1 ^% B
- 0 2 7 1 3 6 10 5 12 11 14
- 2 0 5 3 1 4 8 3 10 9 12
- 7 5 0 7 4 1 5 6 7 6 9
- 1 3 7 0 4 8 9 6 11 10 13
- 3 1 4 4 0 3 7 2 9 8 11
- 6 4 1 8 3 0 4 5 6 5 8
- 10 8 5 9 7 4 0 9 2 1 4
- 5 3 6 6 2 5 9 0 7 8 9
- 12 10 7 11 9 6 2 7 0 1 2
- 11 9 6 10 8 5 1 8 1 0 36 P& E0 x' ^) }1 H/ A; F9 h+ d/ W
* Z5 L6 `5 n9 |! s; A
- Z& z- [# S& H# j! f8 Q14 12 9 13 11 8 4 9 2 3 0
& B" ]; e5 _6 {% J0 }
9 h* m3 H7 p) J# n5 s3 ]路径:b(i,j) i表示起点,j表示终点。3 M a9 R" t/ a l1 D2 F; i4 s
6 _) y: g2 t. j$ g$ V7 Houtpath:
1 C1 ~6 M, u% M% H: l" ]3 E% I! C8 _3 [( e# Z
* R. ]: g% P9 }- x! O
3 m5 u* q' n& x# X: b0 e
" v4 F9 W! Z. u4 c+ O% n& Q- \8 q' ^, E6 d
|
|