闽公网安备 35020302035485号
Distance: 两点间的距离,单位:公里
如:A 点可以先到 B 点,等到 9:30 再送货,再送 C 点(不能先送 D 点,或者 E 点因为 C·点的预约时间为 10:30 – 11:00),送完 C 点再送 E(不能先送 D 点,因为 E 点的距离比 D 点更近),最后送 D 点
要求:使用应聘岗位的技术栈编码实现
-------------------------------------------
为了解决这个问题,我们需要使用一种路径规划算法,考虑到有时间和预约限制,这实际上是一个比常规路径规划算法更复杂的问题。由于有预约时间的限制,我们可以首先按照预约时间对顾客进行排序,然后尽量将接近的地点和没有预约时间的地点插入到路线中,同时确保不违反预约时间。
以下是一个简化的步骤,用于生成一个可能的路线:
1.按预约时间排序:
.顾客B(9:30-10:00)
.顾客C(10:30-11:00)
.顾客D(无预约时间)
.顾客E(无预约时间)
2.计算从A点到所有顾客的距离:
这里我们已经有distance距离矩阵,表示从A点到B、C、D、E的距离。
3.构建初始路线:
.从A点开始,首先到顾客B(因为B是最早需要送货的)。
.接着,我们需要找到在顾客C预约时间之前能够到达的下一个地点。这.可以是E(如果E足够近)或D(如果E太远或不在合适方向上)。
.然后,到顾客C。
.最后,到顾客D(因为没有预约时间限制)。
4.插入无预约时间的顾客:
.在构建路线时,我们需要检查在前往下一个有预约时间的顾客之前,是否有时间插入无预约时间的顾客。
.例如,在前往顾客C之前,如果时间允许,我们可以先送顾客E。
5.优化路线:
.在确定基本路线后,我们可以尝试局部优化,比如交换相邻的无预约时间顾客的位置,以减少总距离或总时间。
6.计算总时间:
.考虑到每个地点的停留时间(10分钟)和旅行时间,计算整个路线的总时间。
7.验证路线:
.确保路线不违反任何预约时间限制。
以下是一个可能的路线示例:
A(6:00出发)
D(A到D耗时100分钟,加停留10分钟,可以在7:50前往B)
B(D到B耗时60分钟,也就是8:50可以到到达B)
C(B到C耗时20分钟,假设9:40出发,10点就能到C)
E(最后送E,因为E没有预约时间限制)
C#代码简要实现:
using System.Collections.Generic; /// <summary> /// Author:Laughing /// Date:2024-05-07 23:09 /// 说明:客户对象基本信息 /// </summary> class Customer { public string Name { get; set; }//客户名称 public DateTime EarliestDeliveryTime { get; set; }//预约的最早时间 public DateTime LatestDeliveryTime { get; set; }//预约的最迟时间 public string Location { get; set; } //当前地点 //在构造函数中完成客户信息初始化 public Customer(string name, DateTime earliest, DateTime latest, string location) { Name = name; EarliestDeliveryTime = earliest; LatestDeliveryTime = latest; Location = location; } } /// <summary> /// Author:Laughing /// Date:2024-05-07 23:42 /// 说明:送货路线算法 /// </summary> class DeliveryRoutePlanner { //用字典存储节点间的时间和距离信息 private Dictionary<(string, string), (int timing, double distance)> distanceMatrix; //构造函数用于初始化信息 public DeliveryRoutePlanner(Dictionary<(string, string), (int timing, double distance)> matrix) { distanceMatrix = matrix; } public List<string> PlanRoute(string startLocation, List<Customer> customers, int stayTimePerCustomer = 10) { var route = new List<string> { startLocation }; // 开始于起点A var currentLocation = startLocation; var currentTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 6, 0, 0); var priorityQueue = new PriorityQueue<Customer, double>(); // 优先级队列,根据到达时间 // 插入有预约时间的顾客到优先队列中 foreach (var customer in customers.Where(c => c.EarliestDeliveryTime != DateTime.MinValue)) { var travelTime = GetTravelTime(currentLocation, customer.Location);//计算当前节点到下一节点所需时间 var arrivalTime = currentTime.AddMinutes(travelTime); if (arrivalTime <= customer.LatestDeliveryTime) { priorityQueue.Enqueue(customer, arrivalTime.Ticks); // 使用Ticks作为优先级 } } // 插入无预约时间的顾客到优先队列中(假设使用无穷大的时间) foreach (var customer in customers.Where(c => c.EarliestDeliveryTime == DateTime.MinValue)) { priorityQueue.Enqueue(customer, long.MaxValue); } while (priorityQueue.TryDequeue(out var customer, out _)) { var travelTime = GetTravelTime(currentLocation, customer.Location); currentTime = currentTime.AddMinutes(travelTime); currentTime = currentTime.AddMinutes(stayTimePerCustomer); // 停留时间 if (currentTime > customer.LatestDeliveryTime && customer.LatestDeliveryTime != DateTime.MinValue) { // 如果超过了预约时间,则跳过该顾客(或进行其他处理) continue; } route.Add(customer.Location); currentLocation = customer.Location; } return route; } /// <summary> /// 获取当前节点到下一节点所需时间 /// </summary> /// <param name="from">当前节点</param> /// <param name="to">下一节点</param> /// <returns>返回矩阵表中定义的从一个节点到另一节点所需时间</returns> private int GetTravelTime(string from, string to) { return distanceMatrix[(from, to)].timing; } } // 使用示例 class Program { static void Main() { // 初始化距离矩阵 var distanceMatrix = new Dictionary<(string, string), (int timing, double distance)> { // 填充A到B、C、D、E的时间和距离... }; var customers = new List<Customer> { // 填充顾客B、C、D、E的信息... }; var planner = new DeliveryRoutePlanner(distanceMatrix);//实例化对象 List<string> minTimeLines = planner.PlanRoute("A", customers);//调用获取最优路径方法,返回最优路径List对象 } }