求覆盖所有仓库送货任务的最小Agent数量技术咨询
最少Agent数量计算:仓库送货调度问题
这个问题本质上是经典的区间调度资源分配问题,核心是用最少的Agent(资源)来完成所有不冲突的送货任务。先明确一下问题中的关键假设(结合你给出的例子):
当Agent为仓库W1{1,2}送货时,需要1小时脱身——意味着Agent在仓库的
startTime时刻开始送货,startTime+1时刻完成任务,且这个1小时窗口必须完全落在仓库的营业时间内(即startTime+1 <= endTime,默认所有仓库都满足这个条件)。
解决思路:贪心算法(排序+最小堆)
这是解决这类问题最高效的方法,时间复杂度为O(n log n)(主要来自排序和堆操作),步骤如下:
- 排序任务:把每个仓库对应的送货时间窗口(
[startTime, startTime+1])按开始时间升序排序;如果开始时间相同,按结束时间升序排序,确保我们按时间顺序处理任务。 - 用最小堆跟踪Agent空闲时间:
- 堆中存储的是每个Agent完成上一个任务后的空闲时间,堆顶是最早能空闲的Agent。
- 遍历每个送货任务:
- 如果堆顶Agent的空闲时间 ≤ 当前任务的开始时间,说明这个Agent可以接手新任务,弹出堆顶,把当前任务的结束时间加入堆。
- 如果堆顶Agent的空闲时间 > 当前任务的开始时间,说明没有Agent能立刻接手,需要新增一个Agent,把当前任务的结束时间加入堆。
- 堆的大小就是所需的最小Agent数:堆里每个元素代表一个Agent的下一次空闲时间,元素个数就是正在工作的Agent总数,也就是最小需要的数量。
Java代码实现
import java.util.*; public class WarehouseDeliveryScheduler { // 你的WareHouse类定义,补充必要的访问方法 static class WareHouse { private int startTime; private int endTime; public WareHouse(int startTime, int endTime) { this.startTime = startTime; this.endTime = endTime; } public int getStartTime() { return startTime; } // 获取送货完成时间(1小时任务) public int getDeliveryEndTime() { return startTime + 1; } } public static int minAgentsNeeded(List<WareHouse> warehouses) { // 边界处理:空列表直接返回0 if (warehouses == null || warehouses.isEmpty()) { return 0; } // 按送货开始时间排序,开始时间相同则按结束时间排序 Collections.sort(warehouses, (a, b) -> { if (a.getStartTime() != b.getStartTime()) { return Integer.compare(a.getStartTime(), b.getStartTime()); } return Integer.compare(a.getDeliveryEndTime(), b.getDeliveryEndTime()); }); // 最小堆:存储Agent的空闲时间 PriorityQueue<Integer> agentFreeTimes = new PriorityQueue<>(); for (WareHouse warehouse : warehouses) { int deliveryStart = warehouse.getStartTime(); int deliveryEnd = warehouse.getDeliveryEndTime(); // 检查是否有Agent可以复用 if (!agentFreeTimes.isEmpty() && agentFreeTimes.peek() <= deliveryStart) { agentFreeTimes.poll(); } // 加入当前任务的结束时间(不管是复用还是新增Agent) agentFreeTimes.offer(deliveryEnd); } return agentFreeTimes.size(); } // 测试示例 public static void main(String[] args) { List<WareHouse> warehouses = Arrays.asList( new WareHouse(1, 3), new WareHouse(2, 4), new WareHouse(1, 2), new WareHouse(3, 5) ); System.out.println("最小需要的Agent数量:" + minAgentsNeeded(warehouses)); // 输出2 } }
另一种思路:时间点计数法
如果你不想用堆,也可以用双指针统计时间点的任务重叠数:
- 收集所有任务的开始时间和结束时间,分别排序。
- 用两个指针遍历两个数组,统计当前同时进行的任务数,最大值就是所需的最小Agent数。
这种方法的时间复杂度也是O(n log n),代码实现起来更简洁,但本质和贪心算法是一致的。
边界情况注意
- 如果存在仓库的
endTime - startTime < 1(比如startTime=2,endTime=2),这类仓库无法安排送货,需要提前过滤或者根据业务需求处理。 - 空仓库列表直接返回0个Agent。
内容的提问来源于stack exchange,提问作者Himanshu Upadhyay
相关产品推荐
相关产品推荐

