综合算法05—考虑换乘的K短路算法

一、问题描述

在路网中,已知站点、线路和线路-站点数据,有条件:
1、考虑到换乘时要花费一定的时间,因此对换乘路径费用要加上换乘时间。
2、当路网复杂时,为了避免多余计算,定义有效路径,使得路径在有效路径范围内。有效路径为最短路径的(1+h)倍。
求满足条件的K短路。

二、算法描述

1.K短路算法:

Step1:令k=1,求出最短路,并加上t换乘;

Step2:k=k+1,求出k短路,并加上t换乘;

Step3:判断,if是有效路径,保存并转Step2;else转Step4;

Step4:删除路径,结束。


2.换乘时间算法(假设换乘时间基于换乘次数):

if 路径所有站点都在线路j上,n=0;

else if 存在i站点,使得起点到i的所有站点都在线路j1上,i到终点的所有站点都在j2上,则n=1;

else if 存在i1、i2,使得起点到i1的所有站点都在线路j1上,i1到i2间所有站点都在j2上,i2到终点的所有站点都在j3上,则n=2;

else n=∞;

t换乘=n*换乘一次的平均时间。

三、算法程序

使用说明:将以下代码分别保存为m文件放在同一个目录下,注意名称不能错,修改案例请打开luwangshuju.m,运行程序请打开KSP.m。
1.fuhaoshuoming.m
fprintf('======================================================================\n');
fprintf('                   《换乘方案算法——不对方案排序》\n');
fprintf('运行环境:MATLAB 8.3.0.532 \n');
fprintf('作者信息:兰州交通大学  刘志祥   QQ:531548824\n');
fprintf('说明:本程序用于在已知路网数据时,通过输入起讫点求直达、一次、二次换乘方案。\n')
fprintf('======================================================================\n\n');
%% 符号体系
%% 路网数据符号
%==========================================================================
% luwangshuju-路网数据,包括站数据(点编号),线数据(线编号),站—线数据(站与线的0-1矩阵,表示站是否在线上),线-站数据(线与站的0-1矩阵,表示线是否包含站),路权数据(如行驶时间或距离)。
% A-起点
% B-终点
% zhan-站集合,本程序中站点以V开头编号
% xian-线集合,可理解为公交车名称,如k102等
% zhan_xian-线与站的关系,表示线路上有哪些站点
%==========================================================================

%% 数据处理符号
%==========================================================================
% zhan_xian_01-线与站的01矩阵,行表示线,列表示站,0表示不在该线,1表示在该线上
% xian_zhan_01-站与线的01矩阵,行表示站,列表示线,0表示线不经过站,1表示经过,与zhan_xian_01互为转置矩阵
%==========================================================================

%% 换乘次数符号
%==========================================================================
% KHc_cishu-换乘次数
% KHc_hcd-换乘点
% KHc_hcqj-换乘区间
% KHc_hcld_a-换乘路段
%==========================================================================

%% K短路算法符号
%==========================================================================
% KPaths-有效路径
% KCosts-有效路径的费用(本文指时间)
%==========================================================================

2.luwangshuju.m
%==========================================================================
% 路网数据
% 运行可得基础路网数据
% 主要计算结果:【输入起讫点 得到路网的站-线-权数据 】
%==========================================================================
%% 输入始发点和目的地
% O=input('O=');
% D=input('D=');
O=2;
D=9;
%==========================================================================

%% 数据for K短路算法
%==========================================================================
% 例1
% Road_Net =[
%     0     3     2   Inf   Inf   Inf   Inf   Inf   Inf
%     3     0   Inf     1     3   Inf   Inf   Inf     2
%     2   Inf     0   Inf     2   Inf   Inf   Inf   Inf
%     Inf     1   Inf     0   Inf     3   Inf   Inf   Inf
%     Inf     3     2   Inf     0     4     3   Inf   Inf
%     Inf   Inf   Inf     3     4     0   Inf   Inf   Inf
%     Inf   Inf   Inf   Inf     3   Inf     0     2   Inf
%     Inf   Inf   Inf   Inf   Inf   Inf     2     0   Inf
%     Inf     2   Inf   Inf   Inf   Inf   Inf   Inf     0];
% zhan=[1 2 3 4 5 6 7 8 9];                                                   %站数据
% xian=[1 2 3 4 5 6];                                                         %线路数据
% xian_zhan={[1 2 4 6],[1 3 5 7 8],[9 2 5 6],[6 4 2 1],[8 7 5 3 1],[6 5 2 9]};%线路包含哪些站
% ==========================================================================

% 例2
%==========================================================================
Road_Net =[
     0     2   Inf     3   Inf   Inf   Inf   Inf   Inf   Inf   Inf   Inf   Inf
     2     0     4   Inf     4   Inf   Inf   Inf   Inf   Inf   Inf     3   Inf
   Inf     4     0   Inf   Inf     3   Inf   Inf   Inf   Inf   Inf   Inf   Inf
     3   Inf   Inf     0     8   Inf     2   Inf   Inf     4   Inf   Inf   Inf
   Inf     4   Inf     8     0     9   Inf     2   Inf   Inf   Inf   Inf   Inf
   Inf   Inf     3   Inf     9     0   Inf   Inf     4   Inf     5   Inf   Inf
   Inf   Inf   Inf     2   Inf   Inf     0     3   Inf   Inf   Inf   Inf   Inf
   Inf   Inf   Inf   Inf     2   Inf     3     0     6   Inf   Inf   Inf     3
   Inf   Inf   Inf   Inf   Inf     4   Inf     6     0   Inf   Inf   Inf   Inf
   Inf   Inf   Inf     4   Inf   Inf   Inf   Inf   Inf     0   Inf   Inf   Inf
   Inf   Inf   Inf   Inf   Inf     5   Inf   Inf   Inf   Inf     0   Inf   Inf
   Inf     2   Inf   Inf   Inf   Inf   Inf   Inf   Inf   Inf   Inf     0   Inf
   Inf   Inf   Inf   Inf   Inf   Inf   Inf     3   Inf   Inf   Inf   Inf     0];
zhan=[1 2 3 4 5 6 7 8 9 10 11 12 13];                                       %站数据
xian=[1 2 3 4 5 6];                                                         %线路数据
xian_zhan={[1 2 3 6 9 8 7 4],[10 4 5 6 11],[12 2 5 8 13],[4 7 8 9 6 3 2 1],...
    [11 6 5 4 10],[13 8 5 2 12]};                                           %线路包含哪些站,注意要和roadnet对应起来,如果线路的始发站和终点站直接相连,即为环线。
%==========================================================================
Cost_of_Transfer=2.5;
H=1;
a=0;
Kmax=inf;
%==========================================================================

3.shujuchuli.m
%==========================================================================
% 数据处理
% 运算依赖于luwangshuju.m
% 主要运算结果【得到普通线站关系的01矩阵】...
%==========================================================================

%以下代码用于换乘算法
%% 线_站单元数组转换为01矩阵
%==========================================================================
xian_zhan_01=zeros(length(xian),length(zhan));
for i=1:length(xian)
    xian_zhan_01(i,xian_zhan{i})=1;
end
zhan_xian_01=xian_zhan_01';
%==========================================================================

%以下代码用于K短路算法
%% 根据路网对路段进行自动标号并求出每个路段的距离
%==========================================================================
for i=1:length(Road_Net)
    for j=1:length(Road_Net)
        if Road_Net(i,j)~=0&Road_Net(i,j)~=inf
            a=a+1;
            luduan_zhan{a}={i,j};
            W_luduan{a}=Road_Net(i,j);
        end
    end
end
%==========================================================================

4.huanchengcishu.m
%==========================================================================
% 换乘次数
% 被KSP.m调用才可计算
% 主要运算结果【换乘次数、换乘点、换乘区间、换乘路段】
%==========================================================================
KHc_hcd{k}=[];
KHc_hcqj{k}=[];
KHc_hcld_a{k}=[];

%% 直达线路
%==========================================================================
KHc_cishu=length(luduan_zhan);                              %最大换乘次数
m1=1;
m2=length(KPaths{k});
for j1=1:length(xian_zhan)
    if all(ismember(KPaths{k}(m1:m2),xian_zhan{j1}))
        if find(O==xian_zhan{j1})<find(D==xian_zhan{j1})
            KHc_cishu=0;
            KHc_hcd{k}={[]};
            KHc_hcqj{k}={[]};
            KHc_hcld_a{k}={[]};
        end
    end
end
%==========================================================================

%% 一次换乘
%==========================================================================
for i=2:length(KPaths{k})-1
    for j1=1:length(xian_zhan)
        for j2=1:length(xian_zhan)
            if KHc_cishu~=0
                if all(ismember(KPaths{k}(1:i),xian_zhan{j1})) & all(ismember(KPaths{k}(i:length(KPaths{k})),xian_zhan{j2}))& j1~=j2
                    if find(O==xian_zhan{j1})<find(KPaths{k}(i)==xian_zhan{j1})& find(D==xian_zhan{j2})>find(KPaths{k}(i)==xian_zhan{j1})
                        KHc_cishu=1;
                        KHc_hcd{k}={KPaths{k}(i)};
                        KHc_hcqj{k}={[KPaths{k}(i) KPaths{k}(i+1)]};
                        for a=1:length(luduan_zhan)
                            if [KPaths{k}(i) KPaths{k}(i+1)]==cell2mat(luduan_zhan{a})
                                KHc_hcld_a{k}={a};
                            end
                        end
                    end
                end
            end
        end
    end
end
%==========================================================================

%% 二次换乘
%==========================================================================
for i1=2:length(KPaths{k})-1
    for i2=i1:length(KPaths{k})-1
        for j1=1:length(xian_zhan)
            for j2=1:length(xian_zhan)
                for j3=1:length(xian_zhan)
                    if KHc_cishu~=0&KHc_cishu~=1
                        if all(ismember(KPaths{k}(1:i1),xian_zhan{j1})) & all(ismember(KPaths{k}(i1:i2),xian_zhan{j2}))& all(ismember(KPaths{k}(i2:length(KPaths{k})),xian_zhan{j3}))
                            if j1~=j2 &j2~=j3 &j1~=j3&KPaths{k}(i1)~=KPaths{k}(i2)
                                if(find(O==xian_zhan{j1})<find(KPaths{k}(i1)==xian_zhan{j1}))  & find(KPaths{k}(i1)==xian_zhan{j2})<find(KPaths{k}(i2)==xian_zhan{j2}) &  find(D==xian_zhan{j3})>find(KPaths{k}(i2)==xian_zhan{j3})
                                    KHc_cishu=2;
                                    KHc_hcd{k}={KPaths{k}(i1) KPaths{k}(i2)};
                                    KHc_hcqj{k}={[KPaths{k}(i1) KPaths{k}(i1+1)];[KPaths{k}(i2) KPaths{k}(i2+1)]};
                                    for a1=1:length(luduan_zhan)
                                        for a2=1:length(luduan_zhan)
                                            if [KPaths{k}(i1) KPaths{k}(i1+1)]==cell2mat(luduan_zhan{a1})&[KPaths{k}(i2) KPaths{k}(i2+1)]==cell2mat(luduan_zhan{a2})
                                                KHc_hcld_a{k}={a1 a2};
                                            end
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
    end
end
%==========================================================================

5.dijkstra.m
function [shortestPath, totalCost] = dijkstra(netCostMatrix, s, d)
n = size(netCostMatrix,1);
for i = 1:n
    farthestPrevHop(i) = i; 
    farthestNextHop(i) = i;
end
visited(1:n) = false;
distance(1:n) = inf;    
parent(1:n) = 0;
distance(s) = 0;
for i = 1:(n-1),
    temp = [];
    for h = 1:n,
        if ~visited(h)  
            temp=[temp distance(h)];
        else
            temp=[temp inf];
        end
    end;
    [t, u] = min(temp);     
    visited(u) = true;         
    for v = 1:n,  
        if ( ( netCostMatrix(u, v) + distance(u)) < distance(v) )
            distance(v) = distance(u) + netCostMatrix(u, v); 
            parent(v) = u;  
        end;
    end;
end;

shortestPath = [];
if parent(d) ~= 0 
    t = d;
    shortestPath = [d];
    while t ~= s
        p = parent(t);
        shortestPath = [p shortestPath];        
        if netCostMatrix(t, farthestPrevHop(t)) < netCostMatrix(t, p)
            farthestPrevHop(t) = p;
        end;
        if netCostMatrix(p, farthestNextHop(p)) < netCostMatrix(p, t)
            farthestNextHop(p) = t;
        end;        
        t = p;
    end;
end;
totalCost = distance(d);

6.KSP.m
clear
clc
%% ===============================================================
% K短路算法+换乘算法
% 运算调用huanchengcishu.m
% 主要运算结果【KPaths KCosts Mxf】
%==========================================================================

%% 1. 输入并处理相关的路网数据
%==========================================================================
luwangshuju;
shujuchuli;
k=1;
n=0;
%==========================================================================

%% 2. K短路算和换乘算法结合,求出有效路径
%==========================================================================
if ismember([O D],zhan) & O~=D
    %% 2.1 调用Dijkstra算法求出最短路路径及费用
    [path costs]=dijkstra(Road_Net, O, D);
    if isempty(path)
        KPaths=[];
        KCosts=[];
    else
        %% 2.2 初始化
        path_number = 1;                %路径从1开始编号
        P{path_number,1}= path;         %单元数组P第一行表示路径
        P{path_number,2}= costs;        %单元数组P第二行表示路径阻抗
        current_P = path_number;
        size_X=1;
        X{size_X}={path_number; path; costs};%1-编号,2-路径,3-阻抗值
        S(path_number)= path(1);        %路径的开始站点
        KPaths{k}= path;
        KCosts{k}= costs;
        
        %% 2.3 调用换乘次数函数
        while (k<Kmax && size_X ~=0)
            huanchengcishu;                                %求出路径k的换乘次数
            KHc_n{k}=KHc_cishu;
            KCosts{k}=KCosts{k}+KHc_cishu*Cost_of_Transfer;%求出考虑换乘后的总费用
            costs=min(cell2mat(KCosts));                   %更新最小费用

            %% 2.4 删除非有效路径
            if  KCosts{k}>(H+1)*costs
                k=k-1;
                KCosts=KCosts(1:k);
                KPaths=KPaths(1:k);
                KHc_n=KHc_n(1:k);
                KHc_hcd=KHc_hcd(1:k);
                KHc_hcqj=KHc_hcqj(1:k);
                KHc_hcld_a=KHc_hcld_a(1:k);
                break
            end
            %% 2.5 关闭已搜索的路径
            for i=1:length(X)
                if  X{i}{1}== current_P
                    size_X = size_X - 1;
                    X(i)=[];
                    break;
                end
            end
            P_= P{current_P,1};
            w = S(current_P);
            for i=1:length(P_)
                if w==P_(i)
                    w_index_in_path=i;                           %找到w在路径中的位置
                end
            end
            %% 2.6 更新路网矩阵
            for index_dev_vertex= w_index_in_path:length(P_)- 1
                temp_luwangjuzhen = Road_Net;
                for i = 1: index_dev_vertex-1
                    v = P_(i);
                    temp_luwangjuzhen(v,:)=inf;
                    temp_luwangjuzhen(:,v)=inf;
                end
                SP_sameSubPath=[];
                index =1;
                SP_sameSubPath{index}=P_;
                for i=1:length(KPaths)
                    if length(KPaths{i})>= index_dev_vertex     %如果路径长度大于index_dev_vertex,即还没有完成搜索
                        if P_(1:index_dev_vertex)== KPaths{i}(1:index_dev_vertex)   %对比当前路径和K路径的前index_dev_vertex个点,如果匹配,继续对比,否则为不匹配
                            index = index+1;                    %匹配成功则自动进入下一个节点对比
                            SP_sameSubPath{index}=KPaths{i};
                        end
                    end
                end
                v_ = P_(index_dev_vertex);
                for j = 1: length(SP_sameSubPath)
                    next=SP_sameSubPath{j}(index_dev_vertex+1);
                    temp_luwangjuzhen(v_,next)=inf;
                end
                sub_P=P_(1:index_dev_vertex);
                costs_sub_P=0;
                for i=1:length(sub_P)-1
                    costs_sub_P=costs_sub_P+Road_Net(sub_P(i),sub_P(i+1));
                end
                [dev_p c]= dijkstra(temp_luwangjuzhen, P_(index_dev_vertex), D);
                if ~isempty(dev_p)
                    path_number=path_number+1;
                    P{path_number,1}=[sub_P(1:end-1) dev_p];     %连接起点到终点的路径
                    P{path_number,2}= costs_sub_P + c ;          %计算子路径及偏差定点到终点费用的和(最终费用)
                    S(path_number)= P_(index_dev_vertex);
                    size_X = size_X + 1;
                    X{size_X}={path_number; P{path_number,1};P{path_number,2}};
                    %                                             更新当前数据(路径编号,路径,路径费用)
                end
            end
            %% 2.7 防错处理,如果指定路径数目大于路网穷举数目,防错,否则最后的结果会发生重复,也可能进入死循环。
            if size_X > 0
                shortestXCosts= X{1}{3};                         %路径费用
                shortestX= X{1}{1};                              %判定路径
                for i=2:size_X
                    if  X{i}{3}< shortestXCosts
                        shortestX= X{i}{1};
                        shortestXCosts= X{i}{3};
                    end
                end
                current_P=shortestX;
                k=k+1;
                KPaths{k}= P{current_P,1};
                KCosts{k}= P{current_P,2};
            else
                k=k+1;
            end
        end
    end
else
    warning('起点或终点不在指定路网中!按任意键请重新输入。。。');
    pause
    KSP
end
%==========================================================================
%% 3.有效路径
%% 3.1 保留有效路径并排序
%==========================================================================
KCosts=cell2mat(KCosts);
yxlj=find(KCosts<min(KCosts)*(1+H));
KCosts=KCosts(yxlj);
[KCosts,yxlj]=sort(KCosts);
KPaths=KPaths(yxlj);
KHc_n=KHc_n(yxlj);
KHc_hcd=KHc_hcd(yxlj);
KHc_hcqj=KHc_hcqj(yxlj);
KHc_hcld_a=KHc_hcld_a(yxlj);
%==========================================================================

%% 3.2 根据有效路径求得路径-路段的01矩阵
%==========================================================================
Mxf=zeros(length(KPaths),length(luduan_zhan));
m=1;
while m<=length(KPaths)
    for i=2:length(KPaths{m})
        for k=1:length(luduan_zhan)
            if isequal(cell2mat(luduan_zhan{k}),KPaths{m}([i-1 i]))
                Mxf(m,k)=1;
            end
        end
    end
    m=m+1;
end
%==========================================================================

%% 3.3 有效路径路径-换乘路段的01矩阵
%==========================================================================
if ~isempty(KHc_hcld_a)
    M=zeros(size(Mxf));
    for k=1:length(KPaths)
        M(k,[cell2mat(KHc_hcld_a{k})])=Cost_of_Transfer;
    end
end
%==========================================================================

%% 4. 主要计算结果
%==========================================================================
KPaths             %有效路径
KCosts             %有效路径的费用(本文指时间)
KHc_n              %换乘次数
KHc_hcd=KHc_hcd    %换乘点
KHc_hcqj=KHc_hcqj  %换乘区间
KHc_hcld_a         %换乘路段
% Mxf                %有效路径与路段的0-1矩阵(为Frank Wolfe算法调用)
% M                  %路径-换乘路段的01矩阵(为Frank Wolfe算法调用)
%==========================================================================

四、算例及运行结果

1.算例1

路网如图1所示,已知站数据、线数据及站-线数据。给定起点v4,终点v8。求路径方案。


1.1 运行结果

修改luwangshuju.m——qidian=4;zhongdian=8;

>> KSP

KPaths = 

    [1x5 double]    [1x7 double]    [1x5 double]


KCosts =

   14.0000   15.5000   17.0000


KHc_n = 

    [2]    [1]    [2]


KHc_hcd = 

    {1x2 cell}    {1x1 cell}    {1x2 cell}


KHc_hcqj = 

    {2x1 cell}    {1x1 cell}    {2x1 cell}


KHc_hcld_a = 

    {1x2 cell}    {1x1 cell}    {1x2 cell}

1.2数据整理
查看并整理得:v4到v8有3条有效路径,排序后为KPaths,费用为KCosts,换乘次数分别为KHc_n,换乘区间为KHc_hcqj(换乘区间是换乘点到其紧后节点),换乘路段为KHc_hcld_a,数据见表1。

表1 算例1计算结果
编号 KPaths KCosts KHc_n KHc_hcqj KHc_hcld_a
k1 4->2->5->7->8 14 2 [2,5] [5,7] [5] [14]
k2 4->2->1->3->5->7->8 15.5 1 [1,3] [2]
k3 4->6->5->7->8 17 2 [6,5] [5,7] [16] [14]


2.算例2
路网如图2所示,已知站数据、线数据及站-线数据。给定起点v2,终点v9。求路径方案。

图2  某简单路网结构图

2.1 运行结果

修改luwangshuju.m——qidian=2;zhongdian=9;

>> KSP

KPaths = 

    [1x4 double]    [1x4 double]    [1x6 double]


KCosts =

   11.0000   14.5000   16.0000


KHc_n = 

    [0]    [1]    [0]


KHc_hcd = 

    {1x1 cell}    {1x1 cell}    {1x1 cell}


KHc_hcqj = 

    {1x1 cell}    {1x1 cell}    {1x1 cell}


KHc_hcld_a = 

    {1x1 cell}    {1x1 cell}    {1x1 cell}

2.2数据整理
查看并整理得:v2到v9有3条有效路径,排序后为KPaths,费用为KCosts,换乘次数分别为KHc_n,换乘区间为KHc_hcqj,换乘路段为KHc_hcld_a,数据见表2。
表2 算例2计算结果
编号 KPaths KCosts KHc_n KHc_hcqj KHc_hcld_a
k1 2->3->6->9 11 0 [] []
k2 2->5->8->9 14.5 1 [8,9] [25]
k3 2->1->4->7->8->9 16 0 [] []

五、结论及展望

在路网站点、线路、站点-线路关系已知时,通过输入起讫点可以计算出路径及其换乘次数。考虑换乘费用和有效路径后,路径数量大大减少,而过滤掉的路径为多余路径,在实际走行中不必考虑。该算法将在多领域得到应用,例如流量分配方面。

六、代码下载

代码下载地址:


猜你喜欢

转载自blog.csdn.net/lzx19901012/article/details/53586597