Floyd-Warshall算法总结

13 篇文章 2 订阅
7 篇文章 6 订阅
本文详细介绍了如何利用Floyd-Warshall算法计算铁路和公路子网络中的最短路径,并构建最小费用矩阵。通过MATLAB实现Floyd算法,求得任意两节点间的最短路径及费用,最后结合LINGO求解器找到钢管运输和订购的最优方案,以降低总成本。此外,还展示了如何在Excel中记录最短路径。
摘要由CSDN通过智能技术生成

Floyd算法能够较快地计算出任意两节点间的最短距离

一般构造距离矩阵,先输入矩阵上三角节点间的距离,再通过转换填好下三角,(需要完整地填完距离矩阵,不然算法运行不了)。

距离矩阵对角线代表该节点到自己的距离,设置为0;两节点间没有直接通过路线的,设置为一个极大数,matlab中可以设置为inf。

Floyd的总体思想是将每个节点都可以看作是一个中转点。对于任意两节点i、j,如果节点i到中转点的距离+中转点到节点j的距离<节点i,j间的距离,就用节点i到中转点的距离+中转点到节点j的距离,代替原先节点i,j间的距离储存入距离矩阵。当遍历中转点后,距离矩阵中储存的即为两节点的最短距离。

我们还可以通过FLoyd算法同时求出任意两节点间最短距离的路径。先构造出初始的记录路径的矩阵R,称之为路由矩阵。如果两节点i,j间有直接路径,即在距离矩阵中不为极大值,那么设置R(i,j)=j,代表从节点i到节点j只需经过节点j就可到达。如果两节点i,j间无直接路径,则设置R(i,j)=0。

设中转点为k,当节点i到中转点k的距离+中转点k到节点j的距离<节点i,j间的距离时,设置R(i,j)=R(i,k)。

可以这样理解,比如当Floyd算法运行完后,我们想查看节点1到节点4的最短路径。点开路由矩阵R,发现R(1,4)=2,表示第一个中转点为2。那么查看矩阵第2行,第4列,R(2,4)=7,第二个中转点7。查看R(7,4)=3,第三个中转点为3。查看R(3,4)=4,第四个中转点为4。也即通过1,2,7,3,4,我们以最短路径从节点1抵达节点4。

floyd_my.m        Floyd算法求任意两节点最短路径

function[D,R]=floyd_my(A)       % A为原距离矩阵,返回D任意两节点间最短路径,R储存最短路径的路线
%Floyd—Warshall算法计算任意两节点间最短路径
n=size(A);
D=A;            %初始化距离矩阵
D=triu(D)+triu(D)';
for i=1:n
        D(i,i)=0;       %距离矩阵对角线置0
end
for i=1:n          %初始化路由矩阵,记录路径
    for j=1:n
        if D(i,j)==inf        %两节点无直接路径,路由设置为0
            R(i,j)=0;
        else
            R(i,j)=j;         %两节点有直接路径,设置为j,代表可以到达节点j
        end
    end
end
for k=1:n          %K中转点
    for i=1:n      %i,j表示任意两节点
        for j=1:n
            if D(i,k)+D(k,j)<D(i,j)
                D(i,j)=D(i,k)+D(k,j);
                R(i,j)=R(i,k);
            end 
        end 
    end
end

DisplayPath.m 打印出任意两点之间的最短路径 

% DisplayPath.m 打印路径函数
function DisplayPath(route, start, dest)
  % 打印出任意两点之间的最短路径 
  % route : 路由表 
  % start : 起点index
  % dest : 终点index  
  while 1        %表达式为真,一直循环直到break
    if(route(start,dest)~=dest)
      fprintf('%s,', num2str(start));
      start = route(start,dest);
    else
      fprintf('%s,',num2str(start));
      fprintf('%s', num2str(dest));
      break;
    end
  end

数模7.8钢管的铁路与运输

先用matlab计算出最小费用矩阵。 

clc,clear
%% 铁路子网络
rail=ones(39,39)*inf;      %距离矩阵,floyd_my中可对矩阵对角线置0
n=size(rail);
rail(1,11)=202;rail(1,15)=20;rail(2,11)=1200;rail(3,16)=690;rail(4,19)=690;rail(5,18)=462;rail(6,23)=70;
rail(7,24)=30;rail(8,9)=450;rail(9,10)=1150;rail(9,12)=80;rail(10,11)=1100;rail(11,16)=720;rail(13,14)=306;
rail(14,15)=195;rail(16,17)=520;rail(17,19)=170;rail(18,19)=88;rail(19,21)=160;rail(20,21)=70;rail(21,22)=320;
rail(22,23)=160;rail(23,24)=290;%输入各节点间的距离
[rail_D,rail_R]=floyd_my(rail);%Floyd—Warshall算法,返回D任意两节点间最短路径,R储存最短路径的路线
% 计算铁路运费矩阵rail_C
rail_price=[20 23 26 29 32 37 44 50 55 60];%单位钢管的铁路运价
len=size(rail_price,2);     %获取矩阵列数
price_bound=[300 350 400 450 500 600 700 800 900 1000];
for i=1:n
    for j=1:n
        for k=1:len
            if rail_D(i,j)==inf
               rail_C(i,j)=inf;
            elseif rail_D(i,j)>1000
                rail_C(i,j)=60+ceil((rail_D(i,j)-1000)/100)*5;% 1000km以上每增加1km至100km运价增加5万
            elseif rail_D(i,j)<=price_bound(k)
                   rail_C(i,j)=rail_price(k);
                   break
            end
        end
    end
end
%% 公路子网络
road=ones(39,39)*inf; %距离矩阵
road(1,31)=31;road(6,38)=110;road(7,39)=20;road(8,26)=3;road(10,28)=600;road(11,32)=12;road(12,27)=2;
road(13,29)=10;road(14,30)=5;road(15,31)=10;road(16,33)=42;road(17,34)=70;road(18,35)=10;
road(20,36)=10;road(22,37)=62;road(23,38)=30;road(24,39)=20;
road(25,26)=104;road(26,27)=301;
road(27,28)=750;road(28,29)=606;road(29,30)=194;road(30,31)=205;road(31,32)=201;road(32,33)=680;
road(33,34)=480;road(34,35)=300;road(35,36)=220;road(36,37)=210;road(37,38)=420;road(38,39)=500;
[road_D,road_R]=floyd_my(road);%Floyd—Warshall算法,返回D任意两节点间最短路径,R储存最短路径的路线
road_C=0.1*road_D;             %公路的运费矩阵
%% 计算总最小运费矩阵
for i=1:n                      %先将铁路子网络和公路子网络组合成一个网络,取其中运费较小的为权
    for j=1:n
       if rail_C(i,j)<=road_C(i,j)
           C(i,j)=rail_C(i,j);
       else
           C(i,j)=road_C(i,j);
       end
    end
end
[Cmin,Rmin]=floyd_my(C);
C_need=Cmin(1:7,25:39);
R_need=Rmin(1:7,25:39);
xlswrite('数模7.8最小运费矩阵.xlsx',C_need,1,'A1')     

再用lingo 解出运输和订购钢管的全部费用最小时,钢管的运输、订购方案。

model:
sets:
station/1..15/:y,z,l;            !y向左铺的钢管数量,z向右铺的钢管数,l需要铺设的钢管数量;
steel/1..7/:s,p,f;             !s该钢厂钢管最大生产量,p钢管生产单位成本;
link(steel,station):c,x;      !c最小运费矩阵,x从钢厂i订购并运输到节点j的钢管数量;
endsets

data:
c=@ole('C:\Users\烟雨潇潇\Desktop\新建文件夹\CSDN\数模7.8最小运费矩阵.xlsx',cmin);!读取最小运费矩阵;
l=104 301 750 606 194 205 201 680 480 300 220 210 420 500 0;
s=800 800 1000 2000 2000 2000 3000;!各钢厂钢管最大生产量;
p=160 155 155 160 155 150 160;!钢管生产单位成本;
enddata

min=@sum(link(i,j):(p(i)+c(i,j))*x(i,j))+0.05*@sum(station(j):y(j)*(y(j)+1)+z(j)*(z(j)+1));!总购运成本;
@for(steel(i):@sum(station(j):x(i,j))>500*f(i));
@for(steel(i):@sum(station(j):x(i,j))<s(i)*f(i));!每个钢厂钢管产量约束;
@for(steel(i):@bin(f(i)));!f=0该钢厂不生产,f=1生产;
@for(station(j):@sum(steel(i):x(i,j))=y(j)+z(j));!订的量等于铺的量;
@for(station(j)|j#ne#15:z(j)+y(j+1)=l(j));              !j不等于15;
@for(station(j):@gin(y(j)));
y(1)=0;z(15)=0;
end

 结果出来还是挺快的。

补充: 用这段代码可以在excel中储存从各钢厂到各铺设节点的最短路径

for i=1:7
    for j=1:15
        start=i;%铁路起点
        dest_rail=R_need(i,j);%铁路终点
        %输出铁路路径
        line=[];       %储存最短路径
        while 1        %表达式为真,一直循环直到break
            if(rail_R(start,dest_rail)~=dest_rail)
                line=[line,start];
                start = rail_R(start,dest_rail);
                if start==0  %如果start=0,说明钢厂直接通过公路连接到铺设点,
                   start=dest_rail;   %需要置为dest_rail,不然会出错
                   break
                end
            else
                line=[line,start];
                break
            end
        end
        %输出公路路径
        start=dest_rail;%公路起点
        dest_road=j+24;%公路终点
        while 1        %表达式为真,一直循环直到break
            if (road_R(start,dest_road)~=dest_road)
                line=[line,start];
                start = road_R(start,dest_road);
            else
                line=[line,start,dest_road];
                k=15*(i-1)+j     %该路径储存在excel的k行
                name=cell(1,1);
                name{1,1}=[int2str(i),',',int2str(dest_road)];  %表示从节点i到节点j的最短路径,cell{}访问cell储存的内容
                A_name=['A',num2str(k)];
                xlswrite('7.8最短路径.xlsx',name(1,1),1,A_name)
                cellnames=['B',num2str(k)];
                xlswrite('7.8最短路径.xlsx',line,1,cellnames)
                break;
            end
        end
    end
end

效果如图: 

 

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值