当前位置: 首页 > article >正文

一种寻路的应用

应用背景

利用长途车进行货物转运的寻路计算。例如从深圳到大连。可以走有很多条长途车的路线。需要根据需求计算出最合适路线。不同的路线的总里程数、总价、需要的时间不一样。客户根据需求进行选择。主要有一些细节:

  1. 全国的长途车车站的数据的更新:

  2. 包括位置、发车班次时间点、车站间的里程数等等。常用的路线有18000多条 


重庆    重庆    重庆万盛客运中心    308    遵义    遵义市长途汽车站
重庆    重庆    重庆万盛客运中心    360    成都    成都北门汽车站
重庆    重庆    重庆渝中长途汽车站    157    武胜    武胜汽车站
重庆    重庆    重庆渝中长途汽车站    340    遵义    遵义市长途汽车站
重庆    重庆    重庆渝中长途汽车站    360    成都    成都北门汽车站
重庆    重庆    重庆渝中长途汽车站    467    巴中    巴中江北客运中心站
重庆    重庆    重庆渝中长途汽车站    502    广元    广元市长途汽车客运站 

  1. 同城转车的处理

  2. 有些城市有多个车站,可以在一个城市里转到另外一个车站,再转运到下一站

  3. 使用发车班次时间表进行总时长的计算

  4. 预留出合理的时间间隔。例如到达某一站是20:30,但是到下一站的车 最晚一班是15:00 点发车。所以只能等第2天的班车。还有的班次可能一周只有2趟车。 有时 到达某一站是15:00  下一站的发车时间也是15:00 这种就只能等下一班,因为赶不上。

代码实现

初始化

班车路线、城市、车站等

constructor TR_Manager.Create;
begin
  _result_path := Tlist<TR_Path>.Create;
  _Dict_Province := TDictionary<Integer, TProvince>.Create();
  _Dict_City := TDictionary<Integer, TCity>.Create();
  _Dict_City_Name := TDictionary<string, TCity>.Create();
  _ProvinceList := Tlist<TProvince>.Create();
  _StationList := Tlist<TStation>.Create();
  _Dict_Station := TDictionary<string, TStation>.Create();
  _StationPathList := Tlist<TStation_Path>.Create();
  _Dict_CityID_Station := TDictionary < Integer, Tlist < TStation >>.Create();
  _Dict_CityID_Xian_Station := TDictionary < Integer, TDictionary < string,
    Tlist<TStation> >>.Create(); // hfg 2016-07-23
  _StationPathNodeList := Tlist<TStation_Path_Node>.Create();
  _Dict_Station_Path_Node := TDictionary<TStation, TStation_Path_Node>.Create();
  _Dict_CityID_Path_Node := TDictionary < Integer, Tlist < TStation_Path_Node
    >>.Create();
  _Node_Tmp := Tlist<TStation_Path_Node>.Create();
  _Node_Tmp_2 := Tlist<TStation_Path_Node>.Create();
  _Node_Tmp_before_end := Tlist<TStation_Path_Node>.Create();
end;

寻路

StationName_Begin: 起点车站

Station_End: 终点车站

max_step: Integer = 6; 最大转车次数

allow_same_city: boolean = false 是否允许同城转运

function TR_Manager.get_path_quick(StationName_Begin: string;
  Station_End: Tlist<TStation>; max_step: Integer = 6;
  allow_same_city: boolean = false): boolean;
var
  Station: TStation;
  node_root, node, node_next: TStation_Path_Node;
  i, k, step, Node_Tmp_Count, Node_Tmp_2_Count,
    Node_Tmp_before_end_count: Integer;
  path: TR_Path;
  list: Tlist;
  city_station_list: Tlist<TStation_Path_Node>;
begin
  Result := false;
  clear_result_path();
  if Station_End = nil then
    exit;

  if Station_End.Count <= 0 then
    exit;
  if not(_Dict_Station.TryGetValue(StationName_begin, Station)) then
    exit;
  if Station.CityID = Station_End[0].CityID then
  begin
    path := TR_Path.Create;
    path.Mileage := 0;
    path.step := 1;
    path.StationList.Add(Station);
    for i := 0 to Station_End.Count - 1 do
    begin
      if Station_End[i].Name <> Station.Name then
      begin
        path.StationList.Add(Station_End[i]);
        Break;
      end;
    end;
    if path.StationList.Count < 2 then
      path.StationList.Add(Station);
    _result_path.Add(path);
  end;
  if not(_Dict_Station_Path_Node.TryGetValue(Station, node_root)) then
    exit;
  for i := 0 to _StationPathNodeList.Count - 1 do
    _StationPathNodeList[i].reset();
  node_root.set_Step(0);
  _Node_Tmp[0] := node_root;
  Node_Tmp_Count := 1;
  Node_Tmp_before_end_count := 0;
  for i := 0 to Station_End.Count - 1 do
  begin
    if _Dict_Station_Path_Node.TryGetValue(Station_End[i], node) then
      node.set_is_before_end();
  end;
  for step := 1 to max_step do
  begin
    Node_Tmp_2_Count := 0;
    for i := 0 to Node_Tmp_Count - 1 do
    begin
      try
        node := _Node_Tmp[i];
        if (node.is_before_end) then
        begin
          _Node_Tmp_before_end[Node_Tmp_before_end_count] := node;
          inc(Node_Tmp_before_end_count);
          if step > 1 then
            Continue;
        end;
        for k := 0 to node.Next_Station.Count - 1 do
        begin
          node_next := node.Next_Station[k].Station_Node_Next;
          if node_next.is_end then
            Continue;
          if not node_next.is_on_path then
          begin
            node_next.path_mileage := node.path_mileage + node.Next_Station
              [k].Mileage;
            node_next.Path_Prior_Station := node;
            node_next.set_Step(step);
            if Node_Tmp_2_Count < _Node_Tmp_2.Count then
              _Node_Tmp_2[Node_Tmp_2_Count] := node_next
            else
              _Node_Tmp_2.Add(node_next);
            inc(Node_Tmp_2_Count);
          end
          else
          begin
            if (node_next.step = step) and (step > 1) then
            begin
              if node.path_mileage + node.Next_Station[k].Mileage < node_next.path_mileage
              then
              begin
                node_next.path_mileage := node.path_mileage + node.Next_Station
                  [k].Mileage;
                node_next.Path_Prior_Station := node;
              end;
            end;
          end;
        end;
        if allow_same_city then
        begin
          if _Dict_CityID_Path_Node.TryGetValue(node.Station.CityID,
            city_station_list) then
          begin
            for k := 0 to city_station_list.Count - 1 do
            begin
              node_next := city_station_list[k];
              if node_next.is_end then
                Continue;
              if not node_next.is_on_path then
              begin
                node_next.path_mileage := node.path_mileage + 0;
                node_next.Path_Prior_Station := node;
                node_next.set_Step(step);
                if Node_Tmp_2_Count < _Node_Tmp_2.Count then
                  _Node_Tmp_2[Node_Tmp_2_Count] := node_next
                else
                  _Node_Tmp_2.Add(node_next);
                inc(Node_Tmp_2_Count);
              end;
            end;
          end;
        end;
      except
        Node_Tmp_2_Count := Node_Tmp_2_Count - 1;
      end;
    end;
    Node_Tmp_Count := 0;
    for i := 0 to Node_Tmp_2_Count - 1 do
    begin
      if _Node_Tmp_2[i].is_on_path then
      begin
        if True then
          if Node_Tmp_Count < _Node_Tmp.Count then
            _Node_Tmp[Node_Tmp_Count] := _Node_Tmp_2[i]
          else
            _Node_Tmp.Add(_Node_Tmp_2[i]);
        inc(Node_Tmp_Count);
      end;
    end;
  end;
  list := Tlist.Create();
  for i := 0 to Node_Tmp_before_end_count - 1 do
  begin
    path := TR_Path.Create;
    node := _Node_Tmp_before_end[i];
    path.Mileage := node.path_mileage + node.to_end_mileage;
    path.StationList.Add(node.end_Node.Station);
    path.StationList.Add(node.Station);
    node_next := node.Path_Prior_Station;
    for step := 1 to max_step + 1 do
    begin
      if node_next = nil then
        Break;
      path.StationList.Add(node_next.Station);
      if node_next.step <= 0 then
        Break;
      node_next := node_next.Path_Prior_Station
    end;
    path.StationList.Reverse();
    list.Add(path);
  end;
  list.Sort(@ComparePath_city);
  for i := 0 to list.Count - 1 do
    _result_path.Add(list[i]);
  FreeAndNil(list);
  Result := _result_path.Count > 0;
end;

操作说明

1、登陆时选择“宝安汽车站”

  1. 发布一条到北京的信息

  1. 在“深圳”里可以看到刚增加的信息

  1. 切换到“湖北武汉”,也可以看到这条信息

  1. 切换到“湖北武汉”,也可以看到这条信息

全部代码

unit U_city_manager;

interface

uses
  System.SysUtils, System.Types, System.Classes, Generics.Collections;

type
  TCounty = class
  private
    _Name: string;
    _CityID: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    property Name: string read _Name write _Name;
    property CityID: Integer read _CityID write _CityID;
  end;

  TProvince = class;

  TCity = class
  private
    _ID: Integer;
    _Name: string;
    _Code: Integer;
    _TelCode: Integer;
    _CountyList: Tlist<TCounty>;
    Province: TProvince;
    procedure clear_CountyList();
  public

    constructor Create;
    destructor Destroy; override;
    property CountyList: Tlist<TCounty> read _CountyList;
    property ID: Integer read _ID write _ID;
    property Name: string read _Name write _Name;
    property Code: Integer read _Code write _Code;
    property TelCode: Integer read _TelCode write _TelCode;
  end;

  TProvince = class
  private
    _ID: Integer;
    _Name: string;
    _CardCode: string;
    _CityList: Tlist<TCity>;
    procedure clear_CityList();
  public
    constructor Create;
    destructor Destroy; override;
    property CityList: Tlist<TCity> read _CityList;
    property ID: Integer read _ID write _ID;
    property Name: string read _Name write _Name;
    property CardCode: string read _CardCode write _CardCode;
  end;

  TStation = class
  private
    _ProvinceName: string;
    _CityID: Integer;
    _CityName: string;
    _Name: string;
    _xian: string; // hfg 2016-07-23
    _address_id: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    property ProvinceName: string read _ProvinceName write _ProvinceName;
    property CityID: Integer read _CityID write _CityID;
    property CityName: string read _CityName write _CityName;
    property Name: string read _Name write _Name;
    property xian: string read _xian write _xian; // hfg 2016-07-23
    property address_id: Integer read _address_id write _address_id;

  end;

  TStation_Path = class
  private
    _Station_Begin: TStation;
    _Station_End: TStation;
    _Mileage: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    property Station_Begin: TStation read _Station_Begin write _Station_Begin;
    property Station_End: TStation read _Station_End write _Station_End;
    property Mileage: Integer read _Mileage write _Mileage;
  end;

  TStation_Path_Node = class;

  TStation_Next = class
  private
    _Station_Node_Next: TStation_Path_Node;
    _Mileage: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    property Station_Node_Next: TStation_Path_Node read _Station_Node_Next
      write _Station_Node_Next;
    property Mileage: Integer read _Mileage write _Mileage;
  end;

  TStation_Path_Node = class
  private
    _Station: TStation;
    _Next_Station: Tlist<TStation_Next>;
    _Prior_Station: Tlist<TStation_Next>;
    _is_on_path: boolean;
    _is_end: boolean;
    _step: Integer;
    _Path_Prior_Station: TStation_Path_Node;
    _path_mileage: Integer;
    _is_before_end: boolean;
    _end_Node: TStation_Path_Node;
    _to_end_mileage: Integer;
    procedure clear_Next_Station();
    procedure clear_Prior_Station();
  public
    constructor Create;
    destructor Destroy; override;
    procedure add_next(next_node: TStation_Path_Node; Mileage: Integer);
    procedure add_Prior(p_node: TStation_Path_Node; Mileage: Integer);
    property Station: TStation read _Station write _Station;
    property Next_Station: Tlist<TStation_Next> read _Next_Station
      write _Next_Station;
    property is_on_path: boolean read _is_on_path;
    property is_end: boolean read _is_end;
    property step: Integer read _step;
    property path_mileage: Integer read _path_mileage write _path_mileage;
    property Path_Prior_Station: TStation_Path_Node read _Path_Prior_Station
      write _Path_Prior_Station;
    property is_before_end: boolean read _is_before_end;
    property to_end_mileage: Integer read _to_end_mileage write _to_end_mileage;
    property end_Node: TStation_Path_Node read _end_Node;

    procedure reset();
    procedure set_Step(v: Integer);
    procedure set_is_before_end();
  end;

  TR_Path = class
  public
    step: Integer;
    Mileage: Integer;
    StationList: Tlist<TStation>;
  public
    constructor Create;
    destructor Destroy; override;
    function get_txt(): string;
    function get_txt_with_city(): string;
  end;

  TR_Manager = class
  private
    _ProvinceList: Tlist<TProvince>;
    _Dict_Province: TDictionary<Integer, TProvince>;
    _Dict_City: TDictionary<Integer, TCity>;
    _Dict_City_Name: TDictionary<string, TCity>;
    _StationList: Tlist<TStation>;
    _Dict_Station: TDictionary<string, TStation>;
    _Dict_CityID_Station: TDictionary<Integer, Tlist<TStation>>;
    _Dict_CityID_Xian_Station
      : TDictionary<Integer, TDictionary<string, Tlist<TStation>>>;
    // hfg 2016-07-23
    _StationPathList: Tlist<TStation_Path>;
    _StationPathNodeList: Tlist<TStation_Path_Node>;
    _Dict_Station_Path_Node: TDictionary<TStation, TStation_Path_Node>;
    _Dict_CityID_Path_Node: TDictionary<Integer, Tlist<TStation_Path_Node>>;
    _Node_Tmp: Tlist<TStation_Path_Node>;
    _Node_Tmp_2: Tlist<TStation_Path_Node>;
    _Node_Tmp_before_end: Tlist<TStation_Path_Node>;
    _result_path: Tlist<TR_Path>;
    procedure clear_result_path();
    procedure clear_ProvinceList();
    procedure clear_StationList();
    procedure clear_StationPathList();
    procedure clear_StationPathNodeList();
    procedure clear_Dict_CityID_Xian_Station(); // hfg 2016-07-23
    procedure make_StationPathNodeList();
  public
    constructor Create;
    destructor Destroy; override;
    property ProvinceList: Tlist<TProvince> read _ProvinceList;
    property result_path: Tlist<TR_Path> read _result_path;
    procedure load_Province(fn: string);
    procedure load_Province_sl(sl: TStringList);
    procedure load_City(fn: string);
    procedure load_City_sl(sl: TStringList);
    procedure load_County(fn: string);
    procedure load_Path(fn: string);
    procedure load_Path_new(fn: string);
    procedure load_Path_new_sl(sl: TStringList); // 2016-10-03
    procedure load_xian(fn: string); // hfg 2016-07-23
    function get_Province_by_id(ID: Integer): TProvince;
    function get_City_by_id(ID: Integer): TCity;
    function get_City_by_name(ProvinceName, city_name: string): TCity;
    function get_City_by_full_name(full_city_name: string): TCity;
    function get_or_add_Station(ProvinceName, CityName, Name: string): TStation;
    function get_or_add_Station_new(city_id, Name, xian: string): TStation;
    procedure get_station_by_city_id(city_id: Integer;
      var list: Tlist<TStation>);
    procedure get_station_by_city_id_xian(city_id: Integer; xian: string;
      var list: Tlist<TStation>); // hfg 2016-07-23
    function get_path_quick(StationName_begin: string;
      Station_End: Tlist<TStation>; max_step: Integer = 6;
      allow_same_city: boolean = false): boolean;

    function get_path_quick_ex(Station_Begin: Tlist<TStation>;
      Station_End: Tlist<TStation>; max_step: Integer = 6;
      allow_same_city: boolean = false): boolean; // 2016-10-01
    function get_StationList: Tlist<TStation>;
    procedure save_Station(fn: string);
    property StationPathList: Tlist<TStation_Path> read _StationPathList;
  end;

implementation

uses u_address_def;

function get_Province_ID_from_City_Code(v: Integer): Integer;
begin
  Result := v div 100;
end;

function ComparePath_city(Item1, Item2: TR_Path): Integer;
begin
  Result := Item1.StationList.Count - Item2.StationList.Count;
  if Result = 0 then
    Result := Item1.Mileage - Item2.Mileage;

end;

{ TR_Manager }
procedure TR_Manager.clear_Dict_CityID_Xian_Station; // hfg 2016-07-23
var
  pair: TPair<Integer, TDictionary<string, Tlist<TStation>>>;
  pair2: TPair<string, Tlist<TStation>>;
begin
  for pair in _Dict_CityID_Xian_Station do
  begin
    for pair2 in pair.Value do
    begin
      pair2.Value.Free
    end;
    pair.Value.Free;
  end;
  _Dict_CityID_Xian_Station.Clear();
end;

procedure TR_Manager.clear_ProvinceList;
var
  i: Integer;
begin
  for i := 0 to _ProvinceList.Count - 1 do
    _ProvinceList[i].Free;
  _ProvinceList.Clear();
  _Dict_Province.Clear();
  _Dict_City.Clear();
  _Dict_City_Name.Clear();
end;

procedure TR_Manager.clear_result_path;
var
  i: Integer;
begin
  for i := 0 to _result_path.Count - 1 do
    _result_path[i].Free;
  _result_path.Clear();
end;

procedure TR_Manager.clear_StationList;
var
  i: Integer;
  pair: TPair<Integer, Tlist<TStation>>;
begin
  _Dict_Station.Clear();
  for i := 0 to _StationList.Count - 1 do
    _StationList[i].Free;
  _StationList.Clear();
  for pair in _Dict_CityID_Station do
  begin
    pair.Value.Free;
  end;
  _Dict_CityID_Station.Clear();
end;

procedure TR_Manager.clear_StationPathList;
var
  i: Integer;
begin
  for i := 0 to _StationPathList.Count - 1 do
    _StationPathList[i].Free;
  _StationPathList.Clear();
end;

procedure TR_Manager.clear_StationPathNodeList;
var
  i: Integer;
  pair: TPair<Integer, Tlist<TStation_Path_Node>>;
begin
  _Dict_Station_Path_Node.Clear();
  for pair in _Dict_CityID_Path_Node do
  begin
    pair.Value.Free;
  end;
  _Dict_CityID_Path_Node.Clear();
  for i := 0 to _StationPathNodeList.Count - 1 do
    _StationPathNodeList[i].Free;
  _StationPathNodeList.Clear();
end;

constructor TR_Manager.Create;
begin
  _result_path := Tlist<TR_Path>.Create;
  _Dict_Province := TDictionary<Integer, TProvince>.Create();
  _Dict_City := TDictionary<Integer, TCity>.Create();
  _Dict_City_Name := TDictionary<string, TCity>.Create();
  _ProvinceList := Tlist<TProvince>.Create();
  _StationList := Tlist<TStation>.Create();
  _Dict_Station := TDictionary<string, TStation>.Create();
  _StationPathList := Tlist<TStation_Path>.Create();
  _Dict_CityID_Station := TDictionary < Integer, Tlist < TStation >>.Create();
  _Dict_CityID_Xian_Station := TDictionary < Integer, TDictionary < string,
    Tlist<TStation> >>.Create(); // hfg 2016-07-23
  _StationPathNodeList := Tlist<TStation_Path_Node>.Create();
  _Dict_Station_Path_Node := TDictionary<TStation, TStation_Path_Node>.Create();
  _Dict_CityID_Path_Node := TDictionary < Integer, Tlist < TStation_Path_Node
    >>.Create();
  _Node_Tmp := Tlist<TStation_Path_Node>.Create();
  _Node_Tmp_2 := Tlist<TStation_Path_Node>.Create();
  _Node_Tmp_before_end := Tlist<TStation_Path_Node>.Create();
end;

destructor TR_Manager.Destroy;
begin
  clear_result_path();
  FreeAndNil(_result_path);
  clear_ProvinceList();
  FreeAndNil(_ProvinceList);
  FreeAndNil(_Dict_Province);
  FreeAndNil(_Dict_City);
  FreeAndNil(_Dict_City_Name);
  clear_StationList();
  FreeAndNil(_StationList);
  FreeAndNil(_Dict_Station);
  clear_StationPathList();
  FreeAndNil(_StationPathList);
  clear_StationPathNodeList();
  FreeAndNil(_StationPathNodeList);
  FreeAndNil(_Node_Tmp);
  FreeAndNil(_Node_Tmp_2);
  FreeAndNil(_Node_Tmp_before_end);
  clear_Dict_CityID_Xian_Station(); // hfg 2016-07-23
  FreeAndNil(_Dict_CityID_Xian_Station); // hfg 2016-07-23
  inherited;
end;

function TR_Manager.get_City_by_full_name(full_city_name: string): TCity;
begin
  if not _Dict_City_Name.TryGetValue(full_city_name, Result) then
    Result := nil;
end;

function TR_Manager.get_City_by_id(ID: Integer): TCity;
begin
  if not _Dict_City.TryGetValue(ID, Result) then
    Result := nil;
end;

function TR_Manager.get_City_by_name(ProvinceName, city_name: string): TCity;
begin
  if not _Dict_City_Name.TryGetValue(ProvinceName + city_name, Result) then
    Result := nil;
end;

function TR_Manager.get_or_add_Station(ProvinceName, CityName, Name: string)
  : TStation;
var
  city: TCity;
  Station: TStation;
  CityID: Integer;
  l: Tlist<TStation>;
begin
  Result := nil;
  if _Dict_Station.TryGetValue(Name, Result) then
    exit;
  if _Dict_City_Name.TryGetValue(ProvinceName + CityName, city) then
    CityID := city.ID
  else
  begin
    CityID := 9999999;
    exit;
  end;
  Station := TStation.Create;
  Station.ProvinceName := ProvinceName;
  Station.CityID := CityID;
  Station.CityName := CityName;
  Station.Name := Name;
  _StationList.Add(Station);
  _Dict_Station.AddOrSetValue(Station.Name, Station);
  if (not _Dict_CityID_Station.TryGetValue(CityID, l)) then
  begin
    l := Tlist<TStation>.Create();
    _Dict_CityID_Station.AddOrSetValue(CityID, l);
  end;
  l.Add(Station);
  Result := Station;
end;

function TR_Manager.get_or_add_Station_new(city_id, Name, xian: string)
  : TStation;
var
  city: TCity;
  Station: TStation;
  CityID: Integer;
  l: Tlist<TStation>;
begin
  Result := nil;
  if _Dict_Station.TryGetValue(Name, Result) then
    exit;
  CityID := strtointdef(city_id, 9999999);
  city := get_City_by_id(CityID);
  if city = nil then
    exit;
  Station := TStation.Create;
  Station.ProvinceName := city.Province._Name;
  Station.CityID := CityID;
  Station.CityName := city.Name;
  Station.Name := Name;
  Station.xian := xian;
  Station.address_id := get_city_xian_id(CityID, xian);
  _StationList.Add(Station);
  _Dict_Station.AddOrSetValue(Station.Name, Station);
  if (not _Dict_CityID_Station.TryGetValue(CityID, l)) then
  begin
    l := Tlist<TStation>.Create();
    _Dict_CityID_Station.AddOrSetValue(CityID, l);
  end;
  l.Add(Station);
  Result := Station;
end;

function TR_Manager.get_path_quick(StationName_begin: string;
  Station_End: Tlist<TStation>; max_step: Integer = 6;
  allow_same_city: boolean = false): boolean;
var
  Station: TStation;
  node_root, node, node_next: TStation_Path_Node;
  i, k, step, Node_Tmp_Count, Node_Tmp_2_Count,
    Node_Tmp_before_end_count: Integer;
  path: TR_Path;
  list: Tlist;
  city_station_list: Tlist<TStation_Path_Node>;
begin
  Result := false;
  clear_result_path();
  if Station_End = nil then
    exit;

  if Station_End.Count <= 0 then
    exit;
  if not(_Dict_Station.TryGetValue(StationName_begin, Station)) then
    exit;
  if Station.CityID = Station_End[0].CityID then
  begin
    path := TR_Path.Create;
    path.Mileage := 0;
    path.step := 1;
    path.StationList.Add(Station);
    for i := 0 to Station_End.Count - 1 do
    begin
      if Station_End[i].Name <> Station.Name then
      begin
        path.StationList.Add(Station_End[i]);
        Break;
      end;
    end;
    if path.StationList.Count < 2 then
      path.StationList.Add(Station);
    _result_path.Add(path);
  end;
  if not(_Dict_Station_Path_Node.TryGetValue(Station, node_root)) then
    exit;
  for i := 0 to _StationPathNodeList.Count - 1 do
    _StationPathNodeList[i].reset();
  node_root.set_Step(0);
  _Node_Tmp[0] := node_root;
  Node_Tmp_Count := 1;
  Node_Tmp_before_end_count := 0;
  for i := 0 to Station_End.Count - 1 do
  begin
    if _Dict_Station_Path_Node.TryGetValue(Station_End[i], node) then
      node.set_is_before_end();
  end;
  for step := 1 to max_step do
  begin
    Node_Tmp_2_Count := 0;
    for i := 0 to Node_Tmp_Count - 1 do
    begin
      try
        node := _Node_Tmp[i];
        if (node.is_before_end) then
        begin
          _Node_Tmp_before_end[Node_Tmp_before_end_count] := node;
          inc(Node_Tmp_before_end_count);
          if step > 1 then
            Continue;
        end;
        for k := 0 to node.Next_Station.Count - 1 do
        begin
          node_next := node.Next_Station[k].Station_Node_Next;
          if node_next.is_end then
            Continue;
          if not node_next.is_on_path then
          begin
            node_next.path_mileage := node.path_mileage + node.Next_Station
              [k].Mileage;
            node_next.Path_Prior_Station := node;
            node_next.set_Step(step);
            if Node_Tmp_2_Count < _Node_Tmp_2.Count then
              _Node_Tmp_2[Node_Tmp_2_Count] := node_next
            else
              _Node_Tmp_2.Add(node_next);
            inc(Node_Tmp_2_Count);
          end
          else
          begin
            if (node_next.step = step) and (step > 1) then
            begin
              if node.path_mileage + node.Next_Station[k].Mileage < node_next.path_mileage
              then
              begin
                node_next.path_mileage := node.path_mileage + node.Next_Station
                  [k].Mileage;
                node_next.Path_Prior_Station := node;
              end;
            end;
          end;
        end;
        if allow_same_city then
        begin
          if _Dict_CityID_Path_Node.TryGetValue(node.Station.CityID,
            city_station_list) then
          begin
            for k := 0 to city_station_list.Count - 1 do
            begin
              node_next := city_station_list[k];
              if node_next.is_end then
                Continue;
              if not node_next.is_on_path then
              begin
                node_next.path_mileage := node.path_mileage + 0;
                node_next.Path_Prior_Station := node;
                node_next.set_Step(step);
                if Node_Tmp_2_Count < _Node_Tmp_2.Count then
                  _Node_Tmp_2[Node_Tmp_2_Count] := node_next
                else
                  _Node_Tmp_2.Add(node_next);
                inc(Node_Tmp_2_Count);
              end;
            end;
          end;
        end;
      except
        Node_Tmp_2_Count := Node_Tmp_2_Count - 1;
      end;
    end;
    Node_Tmp_Count := 0;
    for i := 0 to Node_Tmp_2_Count - 1 do
    begin
      if _Node_Tmp_2[i].is_on_path then
      begin
        if True then
          if Node_Tmp_Count < _Node_Tmp.Count then
            _Node_Tmp[Node_Tmp_Count] := _Node_Tmp_2[i]
          else
            _Node_Tmp.Add(_Node_Tmp_2[i]);
        inc(Node_Tmp_Count);
      end;
    end;
  end;
  list := Tlist.Create();
  for i := 0 to Node_Tmp_before_end_count - 1 do
  begin
    path := TR_Path.Create;
    node := _Node_Tmp_before_end[i];
    path.Mileage := node.path_mileage + node.to_end_mileage;
    path.StationList.Add(node.end_Node.Station);
    path.StationList.Add(node.Station);
    node_next := node.Path_Prior_Station;
    for step := 1 to max_step + 1 do
    begin
      if node_next = nil then
        Break;
      path.StationList.Add(node_next.Station);
      if node_next.step <= 0 then
        Break;
      node_next := node_next.Path_Prior_Station
    end;
    path.StationList.Reverse();
    list.Add(path);
  end;
  list.Sort(@ComparePath_city);
  for i := 0 to list.Count - 1 do
    _result_path.Add(list[i]);
  FreeAndNil(list);
  Result := _result_path.Count > 0;
end;

function TR_Manager.get_path_quick_ex(Station_Begin,
  Station_End: Tlist<TStation>; max_step: Integer;
  allow_same_city: boolean): boolean;
var
  Station: TStation;
  node_root, node, node_next: TStation_Path_Node;
  m, i, k, step, Node_Tmp_Count, Node_Tmp_2_Count,
    Node_Tmp_before_end_count: Integer;
  path: TR_Path;
  list: Tlist;
  city_station_list: Tlist<TStation_Path_Node>;
begin
  Result := false;
  clear_result_path();
  if Station_Begin = nil then
    exit;
  if Station_Begin.Count <= 0 then
    exit;
  if Station_End = nil then
    exit;
  if Station_End.Count <= 0 then
    exit;
  for m := 0 to Station_Begin.Count - 1 do
  begin
    Station := Station_Begin[m];
    if Station.CityID = Station_End[0].CityID then
    begin
      path := TR_Path.Create;
      path.Mileage := 0;
      path.step := 1;
      path.StationList.Add(Station);
      for i := 0 to Station_End.Count - 1 do
      begin
        if Station_End[i].Name <> Station.Name then
        begin
          path.StationList.Add(Station_End[i]);
          Break;
        end;
      end;
      if path.StationList.Count < 2 then
        path.StationList.Add(Station);
      _result_path.Add(path);
    end;
  end;
  for i := 0 to _StationPathNodeList.Count - 1 do
    _StationPathNodeList[i].reset();

  Node_Tmp_Count := 0;
  for m := 0 to Station_Begin.Count - 1 do
  begin
    Station := Station_Begin[m];
    if (_Dict_Station_Path_Node.TryGetValue(Station, node_root)) then
    begin
      _Node_Tmp[Node_Tmp_Count] := node_root;
      node_root.set_Step(0);
      Node_Tmp_Count := Node_Tmp_Count + 1;
    end;
  end;
  if Node_Tmp_Count = 0 then
    exit;
  Node_Tmp_before_end_count := 0;
  for i := 0 to Station_End.Count - 1 do
  begin
    if _Dict_Station_Path_Node.TryGetValue(Station_End[i], node) then
      node.set_is_before_end();
  end;
  for step := 1 to max_step do
  begin
    Node_Tmp_2_Count := 0;
    for i := 0 to Node_Tmp_Count - 1 do
    begin
      try
        node := _Node_Tmp[i];
        if (node.is_before_end) then
        begin
          _Node_Tmp_before_end[Node_Tmp_before_end_count] := node;
          inc(Node_Tmp_before_end_count);
          if step > 1 then
            Continue;
        end;
        for k := 0 to node.Next_Station.Count - 1 do
        begin
          node_next := node.Next_Station[k].Station_Node_Next;
          if node_next.is_end then
            Continue;
          if not node_next.is_on_path then
          begin
            node_next.path_mileage := node.path_mileage + node.Next_Station
              [k].Mileage;
            node_next.Path_Prior_Station := node;
            node_next.set_Step(step);
            if Node_Tmp_2_Count < _Node_Tmp_2.Count then
              _Node_Tmp_2[Node_Tmp_2_Count] := node_next
            else
              _Node_Tmp_2.Add(node_next);
            inc(Node_Tmp_2_Count);
          end
          else
          begin
            if (node_next.step = step) and (step > 1) then
            begin
              if node.path_mileage + node.Next_Station[k].Mileage < node_next.path_mileage
              then
              begin
                node_next.path_mileage := node.path_mileage + node.Next_Station
                  [k].Mileage;
                node_next.Path_Prior_Station := node;
              end;
            end;
          end;
        end;
        if allow_same_city then
        begin
          if _Dict_CityID_Path_Node.TryGetValue(node.Station.CityID,
            city_station_list) then
          begin
            for k := 0 to city_station_list.Count - 1 do
            begin
              node_next := city_station_list[k];
              if node_next.is_end then
                Continue;
              if not node_next.is_on_path then
              begin
                node_next.path_mileage := node.path_mileage + 0;
                node_next.Path_Prior_Station := node;
                node_next.set_Step(step);
                if Node_Tmp_2_Count < _Node_Tmp_2.Count then
                  _Node_Tmp_2[Node_Tmp_2_Count] := node_next
                else
                  _Node_Tmp_2.Add(node_next);
                inc(Node_Tmp_2_Count);
              end;
            end;
          end;
        end;
      except
        Node_Tmp_2_Count := Node_Tmp_2_Count - 1;
      end;
    end;
    Node_Tmp_Count := 0;
    for i := 0 to Node_Tmp_2_Count - 1 do
    begin
      if _Node_Tmp_2[i].is_on_path then
      begin
        if True then
          if Node_Tmp_Count < _Node_Tmp.Count then
            _Node_Tmp[Node_Tmp_Count] := _Node_Tmp_2[i]
          else
            _Node_Tmp.Add(_Node_Tmp_2[i]);
        inc(Node_Tmp_Count);
      end;
    end;
  end;
  list := Tlist.Create();
  for i := 0 to Node_Tmp_before_end_count - 1 do
  begin
    path := TR_Path.Create;
    node := _Node_Tmp_before_end[i];
    path.Mileage := node.path_mileage + node.to_end_mileage;
    path.StationList.Add(node.end_Node.Station);
    path.StationList.Add(node.Station);
    node_next := node.Path_Prior_Station;
    for step := 1 to max_step + 1 do
    begin
      if node_next = nil then
        Break;
      path.StationList.Add(node_next.Station);
      if node_next.step <= 0 then
        Break;
      node_next := node_next.Path_Prior_Station
    end;
    path.StationList.Reverse();
    list.Add(path);
  end;
  list.Sort(@ComparePath_city);
  for i := 0 to list.Count - 1 do
    _result_path.Add(list[i]);
  FreeAndNil(list);
  Result := _result_path.Count > 0;

end;

function TR_Manager.get_Province_by_id(ID: Integer): TProvince;
begin
  if not _Dict_Province.TryGetValue(ID, Result) then
    Result := nil;
end;

function TR_Manager.get_StationList: Tlist<TStation>;
begin
  Result := _StationList;
end;

procedure TR_Manager.get_station_by_city_id(city_id: Integer;
  var list: Tlist<TStation>);
begin
  if not(_Dict_CityID_Station.TryGetValue(city_id, list)) then
    list := nil;
end;

procedure TR_Manager.get_station_by_city_id_xian(city_id: Integer; xian: string;
  var list: Tlist<TStation>); // hfg 2016-07-23
var
  dict: TDictionary<string, Tlist<TStation>>;
begin
  if not _Dict_CityID_Xian_Station.TryGetValue(city_id, dict) then
  begin
    list := nil;
    exit;
  end;
  if not dict.TryGetValue(xian, list) then
  begin
    list := nil;
    exit;
  end;
end;

procedure TR_Manager.load_City(fn: string);
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  load_City_sl(sl);
  FreeAndNil(sl);
end;

procedure TR_Manager.load_City_sl(sl: TStringList);
var
  i, pid: Integer;
  ss: TArray<String>;
  c: TCity;
  p: TProvince;
begin
  _Dict_City.Clear();
  _Dict_City_Name.Clear();
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 3 then
    begin
      c := TCity.Create;
      c.ID := strtointdef(ss[0], 0);
      c.Name := ss[1];
      if length(ss) = 4 then
      begin
        c.Code := strtointdef(ss[2], 0);
        c.TelCode := strtointdef(ss[3], 0);
        pid := get_Province_ID_from_City_Code(c.Code);
      end
      else
      begin
        pid := strtointdef(ss[2], 0);
      end;
      p := get_Province_by_id(pid);
      if p <> nil then
      begin
        p.CityList.Add(c);
        _Dict_City.AddOrSetValue(c.ID, c);
        _Dict_City_Name.AddOrSetValue(p.Name + c.Name, c);
      end;
      c.Province := p;
    end;
    SetLength(ss, 0);
  end;
end;

procedure TR_Manager.load_County(fn: string);
var
  i, pid: Integer;
  sl: TStringList;
  ss: TArray<String>;
  city: TCity;
  county: TCounty;
begin
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 2 then
    begin
      county := TCounty.Create;
      county.CityID := strtointdef(ss[0], 0);
      county.Name := ss[1];
      city := get_City_by_id(pid);
      if city <> nil then
      begin
        city.CountyList.Add(county);
      end;
    end;
    SetLength(ss, 0);
  end;
  FreeAndNil(sl);
end;

procedure TR_Manager.load_Path(fn: string);
var
  i, m: Integer;
  sl: TStringList;
  ss: TArray<String>;
  s_begin, s_end: TStation;
  sp: TStation_Path;
begin
  clear_StationList;
  clear_StationPathList;
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 5 then
    begin
      get_or_add_Station(ss[0], ss[1], ss[2]);
    end;
    SetLength(ss, 0);
  end;
  sl.LoadFromFile(fn);
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 5 then
    begin
      if (_Dict_Station.TryGetValue(ss[2], s_begin)) and
        (_Dict_Station.TryGetValue(ss[5], s_end)) then
      begin
        m := Round(strtointdef(ss[3], 0));
        if m > 0 then
        begin
          sp := TStation_Path.Create;
          sp.Station_Begin := s_begin;
          sp.Station_End := s_end;
          sp.Mileage := m;
          _StationPathList.Add(sp);
        end
        else
        begin

        end;
      end
      else
      begin

      end;
    end;
    SetLength(ss, 0);
  end;
  FreeAndNil(sl);
  make_StationPathNodeList();
end;

procedure TR_Manager.load_Path_new(fn: string);
var
  sl: TStringList;
begin
  // 2016-10-03
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  load_Path_new_sl(sl);
  FreeAndNil(sl);
end;

procedure TR_Manager.load_Path_new_sl(sl: TStringList);
var
  i, m: Integer;
  ss: TArray<String>;
  s_begin, s_end: TStation;
  sp: TStation_Path;
begin
  // 2016-10-03
  clear_StationList;
  clear_StationPathList;
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 6 then
    begin
      get_or_add_Station_new(ss[0], ss[1], ss[2]);
    end;
    SetLength(ss, 0);
  end;

  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 5 then
    begin
      if (_Dict_Station.TryGetValue(ss[1], s_begin)) and
        (_Dict_Station.TryGetValue(ss[5], s_end)) then
      begin
        m := Round(strtointdef(ss[3], 0));
        if m > 0 then
        begin
          sp := TStation_Path.Create;
          sp.Station_Begin := s_begin;
          sp.Station_End := s_end;
          sp.Mileage := m;
          _StationPathList.Add(sp);
        end
        else
        begin

        end;
      end
      else
      begin

      end;
    end;
    SetLength(ss, 0);
  end;
  make_StationPathNodeList();
end;

procedure TR_Manager.load_Province(fn: string);
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  load_Province_sl(sl);
  FreeAndNil(sl);
end;

procedure TR_Manager.load_Province_sl(sl: TStringList);
var
  i: Integer;
  ss: TArray<String>;
  p: TProvince;
begin
  clear_ProvinceList();
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) < 0 then
      Continue;
    if length(ss) >= 2 then
    begin
      p := TProvince.Create;
      p.ID := strtointdef(ss[0], 0);
      p.Name := ss[1];
      if length(ss) >= 3 then
        p.CardCode := ss[2];
      _ProvinceList.Add(p);
      _Dict_Province.AddOrSetValue(p.ID, p);
    end;
    SetLength(ss, 0);
  end;
end;

procedure TR_Manager.load_xian(fn: string); // hfg 2016-07-23
var
  i: Integer;
  sl: TStringList;
  ss: TArray<String>;
  Station: TStation;
  dict: TDictionary<string, Tlist<TStation>>;
  list: Tlist<TStation>;
  pair: TPair<string, TStation>;
  procedure set_xian(v: string);
  begin
    if Station.xian = '' then
      Station.xian := v;
  end;

begin
  clear_Dict_CityID_Xian_Station();
  sl := TStringList.Create;
  sl.LoadFromFile(fn);
  sl.LoadFromFile(fn);
  for i := 0 to sl.Count - 1 do
  begin
    ss := sl[i].Split([#9]);
    if length(ss) = 2 then
    begin
      if _Dict_Station.TryGetValue(ss[0], Station) then
      begin
        set_xian(ss[1]);
      end;
    end;
    SetLength(ss, 0);
  end;
  for pair in _Dict_Station do
  begin
    Station := pair.Value;
    if Station.xian <> '' then
    begin
      if not _Dict_CityID_Xian_Station.TryGetValue(Station.CityID, dict) then
      begin
        dict := TDictionary < string, Tlist < TStation >> .Create();
        _Dict_CityID_Xian_Station.AddOrSetValue(Station.CityID, dict);
      end;
      if not dict.TryGetValue(Station.xian, list) then
      begin
        list := Tlist<TStation>.Create();
        dict.AddOrSetValue(Station.xian, list);
      end;
      list.Add(Station);
    end;
  end;
  FreeAndNil(sl);
end;

procedure TR_Manager.make_StationPathNodeList;
var
  i, cid: Integer;
  p, p2: TStation_Path_Node;
  c_list: Tlist<TStation_Path_Node>;
begin
  _Node_Tmp.Clear();
  clear_StationPathNodeList();
  for i := 0 to _StationList.Count - 1 do
  begin
    p := TStation_Path_Node.Create;
    p.Station := _StationList[i];
    _Dict_Station_Path_Node.AddOrSetValue(p.Station, p);
    _StationPathNodeList.Add(p);
    _Node_Tmp.Add(nil);
    _Node_Tmp_2.Add(nil);
    _Node_Tmp_before_end.Add(nil);
    cid := _StationList[i].CityID;
    if not _Dict_CityID_Path_Node.TryGetValue(cid, c_list) then
    begin
      c_list := Tlist<TStation_Path_Node>.Create;
      _Dict_CityID_Path_Node.AddOrSetValue(cid, c_list);
    end;
    c_list.Add(p);
  end;
  for i := 0 to _StationPathList.Count - 1 do
  begin
    if (_Dict_Station_Path_Node.TryGetValue(_StationPathList[i].Station_Begin,
      p)) and (_Dict_Station_Path_Node.TryGetValue(_StationPathList[i]
      .Station_End, p2)) then
    begin
      p.add_next(p2, _StationPathList[i].Mileage);
      p2.add_Prior(p, _StationPathList[i].Mileage);
    end;
  end;

end;

procedure TR_Manager.save_Station(fn: string);
var
  i: Integer;
  sl: TStringList;
  s: string;
  Station: TStation;
begin
  sl := TStringList.Create;
  for i := 0 to _StationList.Count - 1 do
  begin
    Station := _StationList[i];
    if i = 0 then
      s := 'select ' + Station.CityID.ToString() + ' as  CityID,' +
        QuotedStr(Station.Name) + ' as station'
    else
      s := 'union select ' + Station.CityID.ToString() + ',' +
        QuotedStr(Station.Name);
    sl.Add(s);
  end;
  sl.SaveToFile(fn);
end;

{ TProvince }

procedure TProvince.clear_CityList;
var
  i: Integer;
begin
  for i := 0 to _CityList.Count - 1 do
    _CityList[i].Free;
  _CityList.Clear();
end;

constructor TProvince.Create;
begin
  _CityList := Tlist<TCity>.Create();
end;

destructor TProvince.Destroy;
begin
  clear_CityList();
  FreeAndNil(_CityList);
  inherited;
end;

{ TCity }

procedure TCity.clear_CountyList;
var
  i: Integer;
begin
  for i := 0 to _CountyList.Count - 1 do
    _CountyList[i].Free;
  _CountyList.Clear();
end;

constructor TCity.Create;
begin
  _CountyList := Tlist<TCounty>.Create();
end;

destructor TCity.Destroy;
begin
  clear_CountyList();
  FreeAndNil(_CountyList);
  inherited;
end;

{ TCounty }

constructor TCounty.Create;
begin
  //
end;

destructor TCounty.Destroy;
begin

  inherited;
end;

{ TStation }

constructor TStation.Create;
begin
  //
end;

destructor TStation.Destroy;
begin

  inherited;
end;

{ TStation_Path }

constructor TStation_Path.Create;
begin
  //
end;

destructor TStation_Path.Destroy;
begin

  inherited;
end;

{ TStation_Path_Node }

procedure TStation_Path_Node.add_next(next_node: TStation_Path_Node;
  Mileage: Integer);
var
  n: TStation_Next;
begin
  n := TStation_Next.Create;
  n.Station_Node_Next := next_node;
  n.Mileage := Mileage;
  _Next_Station.Add(n);
end;

procedure TStation_Path_Node.add_Prior(p_node: TStation_Path_Node;
  Mileage: Integer);
var
  n: TStation_Next;
begin
  n := TStation_Next.Create;
  n.Station_Node_Next := p_node;
  n.Mileage := Mileage;
  _Prior_Station.Add(n);
end;

procedure TStation_Path_Node.clear_Next_Station;
var
  i: Integer;
begin
  for i := 0 to _Next_Station.Count - 1 do
    _Next_Station[i].Free;
  _Next_Station.Clear;
end;

procedure TStation_Path_Node.clear_Prior_Station;
var
  i: Integer;
begin
  for i := 0 to _Prior_Station.Count - 1 do
    _Prior_Station[i].Free;
  _Prior_Station.Clear;
end;

constructor TStation_Path_Node.Create;
begin
  _path_mileage := 0;
  _is_on_path := false;
  _step := -1;
  _Next_Station := Tlist<TStation_Next>.Create();
  _Prior_Station := Tlist<TStation_Next>.Create();
end;

destructor TStation_Path_Node.Destroy;
begin
  clear_Next_Station();
  FreeAndNil(_Next_Station);
  clear_Prior_Station();
  FreeAndNil(_Prior_Station);
  inherited;
end;

procedure TStation_Path_Node.reset;
begin
  _is_on_path := false;
  _is_end := false;
  _step := -1;
  _is_before_end := false;
  _path_mileage := 0;
  _Path_Prior_Station := nil;
end;

procedure TStation_Path_Node.set_is_before_end;
var
  i: Integer;
begin
  _is_end := True;
  for i := 0 to _Prior_Station.Count - 1 do
  begin
    if (_Prior_Station[i].Station_Node_Next.is_before_end) then
      if _Prior_Station[i].Station_Node_Next._to_end_mileage < _Prior_Station[i]
        ._Mileage then
        Continue;

    _Prior_Station[i].Station_Node_Next._is_before_end := True;
    _Prior_Station[i].Station_Node_Next._end_Node := self;
    _Prior_Station[i].Station_Node_Next._to_end_mileage :=
      _Prior_Station[i]._Mileage;
  end;
end;

procedure TStation_Path_Node.set_Step(v: Integer);
begin
  _step := v;
  _is_on_path := True;
end;

{ TStation_Next }

constructor TStation_Next.Create;
begin
  //
end;

destructor TStation_Next.Destroy;
begin

  inherited;
end;

{ TR_Path }

constructor TR_Path.Create;
begin
  StationList := Tlist<TStation>.Create();
end;

destructor TR_Path.Destroy;
begin
  FreeAndNil(StationList);
  inherited;
end;

function TR_Path.get_txt: string;
var
  i: Integer;
begin
  Result := '';
  for i := 0 to StationList.Count - 1 do
  begin
    if i > 0 then
      Result := Result + ' -> ';
    Result := Result + StationList[i].Name;
  end;
  Result := Result + ' (' + IntToStr(Mileage) + ')'
end;

function TR_Path.get_txt_with_city: string;
var
  i: Integer;
begin
  Result := '';
  for i := 0 to StationList.Count - 1 do
  begin
    if i > 0 then
      Result := Result + '>';
    Result := Result + StationList[i].CityID.ToString() + '|' +
      StationList[i].Name;
  end;
  Result := Result + ':' + IntToStr(Mileage)
end;

end.


http://www.kler.cn/a/454769.html

相关文章:

  • python递归最多多少层
  • [python学习笔记]对象、引用、浅复制、深复制
  • PHP 数组
  • 探秘仓颉编程语言:使用体验与功能剖析
  • Ollama+OpenWebUI+llama3本地部署
  • 实战分享:开发设计文档模版及编写要点
  • 期权懂|期权入门知识:如何选择期权合约?
  • 1.1、Python3基础语法
  • GitLab的安装与卸载
  • 解决 vue3 中 echarts图表在el-dialog中显示问题
  • leetcode hot100 腐烂的橘子
  • zabbix5.0版本(安装部署+添加服务器+拆分数据库)
  • 产品初探Devops!以及AI如何赋能Devops?
  • 3-Linux 用户管理入门
  • 路由器刷机TP-Link tp-link-WDR566 路由器升级宽带速度
  • VMware安装CentOS 7
  • Spring 容器与配置类
  • 面试题整理19----Metric的几种类型?分别是什么?
  • 一文快速预览经典深度学习模型(二)——迁移学习、半监督学习、图神经网络(GNN)、联邦学习
  • 输入输出流 - cin, cout 的使用
  • 6、MHA
  • 【WRF模拟】如何得到更佳的WRF模拟效果?
  • Lockpass(密码管理器) v0.0.14
  • OpenTK 中几何着色器的使用
  • 全国硕士研究生入学考试(考研)热门问题解答
  • 智慧城市超声波气象站