一种寻路的应用

news2024/12/27 13:49:25

应用背景

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

  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.coloradmin.cn/o/2266423.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2. FPGA基础了解--全局网络

前言 引入扇出的概念介绍FPGA中的全局网络为后续时序优化埋下伏笔 扇出 在FPGA设计中扇出是一个重要的概念&#xff0c;所谓的扇出就是一个控制信号所能控制的数据信号的总个数&#xff0c;比如ctrl信号的扇出就是16 reg ctrl 0; reg [15:0] out 0; always (posedge c…

Excel中一次查询返回多列

使用Excel或wps的时候&#xff0c;有时候需要一次查询返回多列内容&#xff0c;这种情况可以选择多次vlookup或者多次xlookup&#xff0c;但是这种做法费时费力不说&#xff0c;效率还有些低下&#xff0c;特别是要查询的列数过多时。我放了3种查询方法&#xff0c;效果图&…

智能化军事【五】精确制导武器智能化实现

文章目录 前言精确制导武器智能化实现基于深度学习实现的智能化功能基于强化学习实现的智能化功能强化学习深度强化学习 网络模型轻量化网络剪枝&#xff08;通道剪枝&#xff09;技术层剪枝权值量化技术低秩近似技术知识蒸馏技术强化学习联合训练 解决有效训练样本不足或获取困…

解锁高效密码:适当休息,让学习状态满格

一、“肝帝” 的困境 在当今竞争激烈的职场中&#xff0c;“肝帝” 现象屡见不鲜。超长工时仿佛成为了许多行业的 “标配”&#xff0c;从互联网企业的 “996”“007”&#xff0c;到传统制造业的轮班倒、无休无止的加班&#xff0c;员工们的工作时间被不断拉长。清晨&#xff…

asp.net 高校学生勤工俭学系统设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm 等开发框架&#xff09; vue .net php python(flask Django) 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找…

WebRTC服务质量(12)- Pacer机制(04) 向Pacer中插入数据

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

RTMW:实时多人2D和3D 全人体姿态估计

单位&#xff1a;上海AI实验室 代码&#xff1a;mmpose/tree/main/projects/rtmpose 系列文章目录 RTMO: 面向高性能单阶段的实时多人姿态估计 目录 系列文章目录摘要一、背景二、相关工作2.1 自上而下的方法。2.2 坐标分类。2.3 3D Pose 3 实验方法3.1.1 任务限制3.1.3训练技…

AI智能养站神器-SEO助理原创文章批量生成发布工具

很多站长最头疼的就是网站每天的内容更新&#xff0c;因为不知道写什么&#xff0c;采集被人的文章又会被定义为抄袭&#xff0c;而且现在伪原创已经没有多大的效果了&#xff0c;所以今天给大家分享的就是一款AI智能养战神器-SEO助理原创文章批量生成发布工具。 这款工具支持…

用Python开启人工智能之旅(三)常用的机器学习算法与实现

第三部分&#xff1a;常用的机器学习算法与实现 用Python开启人工智能之旅&#xff08;一&#xff09;Python简介与安装 用Python开启人工智能之旅&#xff08;二&#xff09;Python基础 用Python开启人工智能之旅&#xff08;三&#xff09;常用的机器学习算法与实现 用Pyt…

FD(File Descriptor)泄漏

File Descriptor是Linux下概念&#xff0c;fd 是 int类型非负数&#xff01; 进程打开File&#xff0c;Socket&#xff0c;Pipe后生成一个File Descriptor&#xff0c;它是打开这个系统资源的标识符。 Linux每个进程fd最大1024个&#xff0c;超过之后进程 crash&#xff0c;c…

英语单词拼读小程序开发制作介绍

英语单词拼读小程序开发制作介绍本英语单词拼读小程序系统开发的主要功能有&#xff1a; 1、按年级分类展示每个年级阶段的英语单词信息。 2、点击选择的单词进入单词拼读页面&#xff0c;展示英语单词的拼读音标、中文意思、单词发音、拆分词汇发音、用户通过朗读发音对比。通…

TCP客户端模拟链接websocket服务端发送消息(二)

兄弟们&#xff0c;我来填坑了&#xff0c;o(╥﹏╥)o o(╥﹏╥)o o(╥﹏╥)o o(╥﹏╥)o o(╥﹏╥)o o(╥﹏╥)o&#xff0c;前几天写了个tcp模拟websocket客户端的以为完成&#xff0c;后面需要发送消息给服务端&#xff0c;以为简单不就是一个发送消息么&#xff0c;这不是一…

Docker 镜像加速访问方案

在数字化时代&#xff0c;Docker以其轻量级和便捷性成为开发者和运维人员的首选容器技术。然而自2023年5月中旬起&#xff0c;Docker Hub 的访问速度较慢或不稳定&#xff0c;这对依赖Docker Hub拉取镜像的用户来说无疑是一个挑战。本文将提供 Docker Hub 访问的一系列替代方案…

牛客网刷题 ——C语言初阶——BC112小乐乐求和

1.牛客网刷题 ——C语言初阶 牛客网&#xff1a;BC112小乐乐求和 小乐乐最近接触了求和符号Σ&#xff0c;他想计算的结果。但是小乐乐很笨&#xff0c;请你帮助他解答。 输入描述: 输入一个正整数n (1 ≤ n ≤ 109) 输出描述: 输出一个值&#xff0c;为求和结果。 示例1 输…

Eclipse常用快捷键详解

文章目录 Eclipse常用快捷键详解一、引言二、编辑快捷键三、选择和移动快捷键四、行操作快捷键五、搜索和导航快捷键六、调试快捷键七、重构快捷键八、其他快捷键九、使用案例场景一&#xff1a;代码编写代码示例 场景二&#xff1a;代码调试场景三&#xff1a;代码重构代码示例…

clickhouse测试报告

​一、背景 针对当前实施的项目&#xff0c;面临着两个主要挑战&#xff1a;一是需要存储更详细的原始数据和中间数据&#xff0c;二是现有基于MySQL的数据存储解决方案在数据量增长时性能受限&#xff0c;特别是在进行跨年历史数据的即时分析时。为了解决这些问题&#xf…

windows和mac共享文件夹访问教程

mac共享文件夹&#xff0c;windows访问&#xff1a; mac上开启文件夹共享&#xff0c;并添加文件夹和用户&#xff0c;然后windows 上 在windows上快捷键 win r 打开运行&#xff0c;按如下格式输入mac设备的IP地址&#xff1a; 就可以访问了&#xff1a; windows共享文件夹…

FPGA自学之路:到底有多崎岖?

FPGA&#xff0c;即现场可编程门阵列&#xff0c;被誉为硬件世界的“瑞士军刀”&#xff0c;其灵活性和可编程性让无数开发者为之倾倒。但谈及FPGA的学习难度&#xff0c;不少人望而却步。那么&#xff0c;FPGA自学之路到底有多崎岖呢&#xff1f; 几座大山那么高&#xff1f;…

两分钟掌握 TDengine 全部写入方式

1. 背景 TDengine 写入过程会涉及很多概念&#xff0c;这些概念目前你是不是还一团乱&#xff0c;参数绑定写入、无模式写入、websocket 写入、RESTFUL 写入 、各种连接器写入等等一堆的写入&#xff0c;都是做什么的&#xff0c;不明白&#xff0c;这里花两分钟时间给你彻底整…

GJB289A总线典型网络理论分析

1.GJB289A总线典型网络理论分析 根据相关标准&#xff0c;“某个支路的故障不影响整个系统”及耦合变压器特性&#xff0c;本文在仿真与实测时均采用典型的一发一收两端口总线网络。 典型两端口总线网络电气结构如图1所示&#xff0c;包含终端匹配电阻、故障隔离电阻、耦合变…