• matlab实践(四):利用改进的遗传算法解决TSP问题


    1.TSP问题

    TSP问题可以描述为:现有一些节点,节点和节点之间均可相连形成边,节点之间的边存在距离,需要找到一个遍历方案先后访问所有的点,使的遍历的总距离最短。这里我们提供80个节点的经纬度,以便我们更好的计算点与点之间的距离。

    2.数据

    1. x=[850.712674289007 929.608866756663 582.790965175840 879.013904597178 0.522375356944771 612.566469483999 527.680069338442 801.347605521952 498.094291196390 574.661219130188 738.640291995402 246.734525985975 83.4828136026227 660.944557947342 890.752116325322 769.029085335896 928.313062314188 16.9829383372613 862.710718699670 844.855674576263 552.291341538775 31.9910157625669 362.411462273053 489.569989177322 123.083747545945 146.514910614890 42.6524109111434 281.866855880430 695.163039444332 535.801055751113 123.932277598070 852.998155340816 270.294332292698 564.979570738201 417.028951642886 947.933121293169 105.709426581721 166.460440876421 573.709764841198 931.201384608250 737.841653797590 860.440563038232 984.398312240972 785.558989265031 177.602460505865 133.931250987971 939.141706069548 295.533834475356 467.068187028852 25.2281814930363 559.032544988695 347.879194327261 54.2394844411296 662.808061960974 898.486137834300 988.417928784981 706.917419322763 287.849344815137 464.839941625137 818.204038907671 178.116953886766 56.7046890682912 335.848974676925 208.946673993135 675.391177336247 912.132474239623 745.546073701717 561.861425281637 597.211350337855 134.122932828682 894.941675440814 242.486558936719 441.722057064424 897.191350973572 93.3705167550930 456.057666843742 995.389727655092 297.346815887922 298.243971887764 505.428142457703];
    2. y=[560.559527354885 696.667200555228 815.397211477421 988.911616079589 865.438591013025 989.950205708831 479.523385210219 227.842935706042 900.852488532005 845.178185054037 585.987035826476 666.416217319468 625.959785171583 729.751855317221 982.303222883606 581.446487875398 580.090365758442 120.859571098558 484.296511212103 209.405084020935 629.883385064421 614.713419117141 49.5325790420612 192.510396062075 205.494170907680 189.072174472614 635.197916859882 538.596678045340 499.116013482590 445.183165296042 490.357293468018 873.927405861733 208.461358751314 640.311825162758 205.975515532243 82.0712070977259 142.041121903998 620.958643935308 52.0778902858696 728.661681678271 63.4045006928182 934.405118961213 858.938816683866 513.377418587575 398.589496735843 30.8895487449515 301.306064586392 332.936281836175 648.198406466157 842.206612419335 854.099949273443 446.026648055103 177.107533789109 330.828995203305 118.155198446711 539.982099037929 999.491620097705 414.522538893108 763.957078491957 100.221540195492 359.634913482080 521.885673661279 175.669029675661 905.153559004464 468.468199903997 104.011574779379 736.267455596639 184.194097515527 299.936990089789 212.601533358843 71.4528127870445 53.7543922087138 13.2832004672525 196.658191367632 307.366899587920 101.669393624755 332.092833452499 62.0452213196326 46.3512648981808 761.425886690113];

    其中x代表经度,y代表纬度。

    3.遗传算法

    step1:初始化种群

    step2:计算适应度

    step3:选择,交叉,变异算子

    step4:  判断是否为最优解

    适应度函数

    1. function [ fitnessvar, sumDistances,minPath, maxPath ] = fitness( distances, pop )
    2. % 计算整个种群的适应度值
    3. [popSize, col] = size(pop);
    4. sumDistances = zeros(popSize,1);
    5. fitnessvar = zeros(popSize,1);
    6. for i=1:popSize
    7. for j=1:col-1
    8. sumDistances(i) = sumDistances(i) + distances(pop(i,j),pop(i,j+1));
    9. end
    10. end
    11. minPath = min(sumDistances);
    12. maxPath = max(sumDistances);
    13. for i=1:length(sumDistances)
    14. fitnessvar(i,1)=(maxPath - sumDistances(i,1)+0.000001) / (maxPath-minPath+0.00000001);
    15. end
    16. end

     交叉

    1. function [childPath] = crossover(parent1Path, parent2Path, prob)
    2. % 交叉
    3. random = rand();
    4. if prob >= random
    5. [l, length] = size(parent1Path);
    6. childPath = zeros(l,length);
    7. setSize = floor(length/2) -1;
    8. offset = randi(setSize);
    9. for i=offset:setSize+offset-1 %交叉段
    10. childPath(1,i) = parent1Path(1,i); %先将交叉段复制
    11. end
    12. iterator = i+1;
    13. j = iterator;
    14. while any(childPath == 0) %对于交叉段以外位置操作
    15. if j > length
    16. j = 1;
    17. end
    18. if iterator > length
    19. iterator = 1;
    20. end
    21. if ~any(childPath == parent2Path(1,j))
    22. childPath(1,iterator) = parent2Path(1,j);
    23. iterator = iterator + 1;
    24. end
    25. j = j + 1;
    26. end
    27. else
    28. childPath = parent1Path;
    29. end
    30. end

     更新

    1. function [ mutatedPath ] = mutate( path, prob )
    2. %对指定的路径利用指定的概率进行更新
    3. random = rand();
    4. if random <= prob
    5. [l,length] = size(path);
    6. index1 = randi(length);
    7. index2 = randi(length);
    8. %交换
    9. temp = path(l,index1);
    10. path(l,index1) = path(l,index2);
    11. path(l,index2)=temp;
    12. end
    13. mutatedPath = path;
    14. end

    计算距离

    1. function [ distances ] = calculateDistance( city )
    2. %计算距离
    3. [~, col] = size(city);
    4. distances = zeros(col);
    5. for i=1:col
    6. for j=1:col
    7. distances(i,j)= distances(i,j)+ sqrt( (city(1,i)-city(1,j))^2 + (city(2,i)-city(2,j))^2 );
    8. end
    9. end
    10. end

    画图

    1. function [ output_args ] = paint( cities, pop, minPath, totalDistances,gen)
    2. gNumber=gen;
    3. [~, length] = size(cities);
    4. xDots = cities(1,:);
    5. yDots = cities(2,:);
    6. %figure(1);
    7. title('GA TSP');
    8. plot(xDots,yDots, 'p', 'MarkerSize', 14, 'MarkerFaceColor', 'blue');
    9. xlabel('经度');
    10. ylabel('纬度');
    11. axis equal
    12. hold on
    13. [minPathX,~] = find(totalDistances==minPath,1, 'first');
    14. bestPopPath = pop(minPathX, :);
    15. bestX = zeros(1,length);
    16. bestY = zeros(1,length);
    17. for j=1:length
    18. bestX(1,j) = cities(1,bestPopPath(1,j));
    19. bestY(1,j) = cities(2,bestPopPath(1,j));
    20. end
    21. title('GA TSP');
    22. plot(bestX(1,:),bestY(1,:), 'red', 'LineWidth', 1.25);
    23. legend('城市', '路径');
    24. axis equal
    25. grid on
    26. %text(5,0,sprintf('迭代次数: %d 总路径长度: %.2f',gNumber, minPath),'FontSize',10);
    27. drawnow
    28. hold off
    29. end

    主函数

    1. clear;
    2. clc;
    3. tStart = tic; % 算法计时器
    4. %%%%%%%%%%%%自定义参数%%%%%%%%%%%%%
    5. cities=importdata('cities80.mat');
    6. cityNum=80;
    7. maxGEN = 500; % 最大迭代步长
    8. popSize = 100; % 遗传算法种群大小
    9. crossoverProbabilty = 0.9; %交叉概率
    10. mutationProbabilty = 0.1; %变异概率
    11. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    12. gbest = Inf; %初始最佳路径距离
    13. distances = calculateDistance(cities); %计算两两城市之间距离,生成一个方阵
    14. % 生成种群,每个个体代表一个路径
    15. pop = zeros(popSize, cityNum); %生成 popSize x cityNum 方阵,存储种族群
    16. for i=1:popSize
    17. pop(i,:) = randperm(cityNum); %随机生成一个解,即城市-城市-...链,初始种群
    18. end
    19. offspring = zeros(popSize,cityNum); %子代
    20. %保存每代的最小路劲便于画图
    21. minPathes = zeros(maxGEN,1);
    22. % GA算法
    23. for gen=1:maxGEN
    24. % 计算适应度的值,即路径总距离
    25. [fval, sumDistance, minPath, maxPath] = fitness(distances, pop);
    26. % 轮盘赌选择
    27. tournamentSize=4; %设置大小
    28. for k=1:popSize
    29. % 选择父代进行交叉
    30. tourPopDistances=zeros( tournamentSize,1);
    31. for i=1:tournamentSize
    32. randomRow = randi(popSize); %生成1-popSize之间的一个伪随机数
    33. tourPopDistances(i,1) = sumDistance(randomRow,1);
    34. end
    35. % 选择最好的,即距离最小的
    36. parent1 = min(tourPopDistances);
    37. [parent1X,parent1Y] = find(sumDistance==parent1,1, 'first');
    38. %找到parent1的下标,即个体序号,[parent1X,parent1Y]=[row,col]
    39. parent1Path = pop(parent1X(1,1),:);
    40. for i=1:tournamentSize
    41. randomRow = randi(popSize);
    42. tourPopDistances(i,1) = sumDistance(randomRow,1);
    43. end
    44. parent2 = min(tourPopDistances);
    45. [parent2X,parent2Y] = find(sumDistance==parent2,1, 'first');
    46. parent2Path = pop(parent2X(1,1),:);
    47. subPath = crossover(parent1Path, parent2Path, crossoverProbabilty);%交叉
    48. subPath = mutate(subPath, mutationProbabilty);%变异
    49. offspring(k,:) = subPath(1,:);
    50. minPathes(gen,1) = minPath;
    51. end
    52. fprintf('代数:%d 最短路径:%.2fKM \n', gen,minPath);
    53. % 更新
    54. pop = offspring;
    55. % 画出当前状态下的最短路径
    56. if minPath < gbest
    57. gbest = minPath;
    58. paint(cities, pop, gbest, sumDistance,gen);
    59. end
    60. end
    61. figure
    62. plot(minPathes, 'MarkerFaceColor', 'red','LineWidth',1);
    63. title('收敛曲线图(每一代的最短路径)');
    64. set(gca,'ytick',500:100:5000);
    65. ylabel('路径长度');
    66. xlabel('迭代次数');
    67. grid on
    68. tEnd = toc(tStart);
    69. fprintf('时间:%d 分 %f 秒.\n', floor(tEnd/60), rem(tEnd,60));

    结果 

    783ec61b149f4707bbe744496ac9e8f4.png

    7121f23582fa4e94a9566938bcb78d2f.png

    4.改进的遗传算法

    1. clc;clear;
    2. tStart = tic; % 算法计时器
    3. %%%%%初始化参数
    4. C= importdata('cities80.mat')';
    5. NP=200;
    6. N=size(C,1);
    7. G=500;
    8. %%%%%初始种群
    9. f=zeros(N,NP);
    10. for i=1:NP
    11. f(:,i)=randperm(N);
    12. end
    13. len=zeros(1,NP);
    14. %%%%%任意城市间距离
    15. D=zeros(N);
    16. for i=1:N
    17. for j=1:N
    18. D(i,j)=((C(i,1)-C(j,1))^2 + (C(i,2)-C(j,2))^2)^0.5;
    19. end
    20. end
    21. %%%%%计算路径长度--亲和度
    22. for i=1:NP
    23. len(i)=func3(D,f(:,i),N);
    24. end
    25. [sortlen ,index]=sort(len);
    26. sortf=f(:,index);
    27. NC=10;
    28. gen=1;
    29. %%%%%免疫循环
    30. while gen<=G
    31. %%%%%选择激励度前NP/2个体进入免疫操作
    32. for i=1:NP/2
    33. a=sortf(:,i);
    34. ca=repmat(a,1,NC);
    35. for j=1:NC
    36. p1=floor(1+N*rand);
    37. p2=floor(1+N*rand);
    38. while p1==p2
    39. p1=floor(1+N*rand);
    40. p2=floor(1+N*rand);
    41. end
    42. tmp=ca(p1,j);
    43. ca(p1,j)=ca(p2,j);
    44. ca(p2,j)=tmp;
    45. end
    46. ca(:,1)=a;
    47. %%%%%克隆抑制
    48. for j=1:NC
    49. calen(j)=func3(D,ca(:,j),N);
    50. end
    51. [sortcalen,index]=sort(calen);
    52. sortca=ca(:,index);
    53. af(:,i)=sortca(:,1);
    54. alen(i)=sortcalen(1);
    55. end
    56. %%%%%免疫种群与新生种群合并--种群刷新
    57. for i=1:NP/2
    58. bf(:,i)=randperm(N);
    59. blen(i)=func3(D,bf(:,i),N);
    60. end
    61. f=[af bf];
    62. len=[alen blen];
    63. [sortlen, index]=sort(len);
    64. sortf=f(:,index);
    65. fprintf('代数:%d 最短路径:%.2fKM \n', gen,trace(gen));
    66. gen=gen+1;
    67. trace(gen)=sortlen(1);
    68. paint(C', f, trace(end), len,gen);
    69. end
    70. %%%%%输出优化结果
    71. bestf=sortf(:,1);
    72. bestlen=trace(end);
    73. % for i=1:N-1
    74. % plot([C(bestf(i),1),C(bestf(i+1),1)],[C(bestf(i),2),C(bestf(i+1),2)],'o-');
    75. % hold on;
    76. % end
    77. % plot([C(bestf(N),1),C(bestf(1),1)],[C(bestf(N),2),C(bestf(1),2)],'ro-');
    78. % title(['最短距离:',num2str(bestlen)]);
    79. figure
    80. plot(trace, 'MarkerFaceColor', 'red','LineWidth',1);
    81. title('收敛曲线图(每一代的最短路径)');
    82. set(gca,'ytick',0:10000:50000);
    83. ylabel('路径长度');
    84. xlabel('迭代次数');
    85. grid on
    86. tEnd = toc(tStart);
    87. fprintf('时间:%d 分 %f 秒.\n', floor(tEnd/60), rem(tEnd,60));
    88. %%%%%路径长度函数
    89. function result = func3(D,f,N)
    90. len=D(f(1),f(N));
    91. for j=2:N
    92. len=D(f(j),f(j-1))+len;
    93. end
    94. result=len;
    95. end

    结果

     f56e6868dfac4213a89d5dd894e80160.png

    01dfbfe726654f03825be03fdaf410d7.png

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    LeetCode279:完全平方数,动态规划解法超过46%,作弊解法却超过97%
    win10查看wifi密码
    C语言,洛谷题,压缩技术2.0
    【乐吾乐2D可视化组态编辑器】导出HTML,下载离线部署包
    DTCloud 第1天
    2022/8/11
    CDR最新CorelDRAWX8安装步骤教程
    kubernetes-pod的更新策略与回滚策略
    英语翻译器-免费英语自动批量翻译器
    ky使用教程(基于fetch的小巧优雅js的http客服端)
  • 原文地址:https://blog.csdn.net/m0_68926749/article/details/132638891