• 算法面试题:选出外卖小哥送货最顺线路
  • 发布于 1周前
  • 35 热度
    2 评论
  • 心已凉
  • 8 粉丝 35 篇博客
  •   
题目:请以外卖小哥当前位置为起点,根据各顾客之间的最短距离,自动按正确顺序排列路线的各个地点。这样做的目的是将顾客的地点连接成一条最适合的线路,方便外卖小哥按此路线送货。
条件:
1. 外卖小哥当前位置为 A 点,出发时间为:6:00
2. 顾客 B:预约时间 9:30 到 10:00
3. 顾客 C:预约时间为:10:30 到 11:00
4. 顾客 D:没有预约时间
5. 顾客 E:没有预约时间
6. 每个地点停留时间为:10 分钟
7. 每个地点到另一个地点所需要的时间以及距离如下表:
A- E 对应 5 个地点;A 点为开始位置:timings 两个地点间要花费的时间单位:分钟

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对象
    
       }
    }

  • 2024/5/8 0:13:00 [ 0 ] [ 0 ] 回复