排队等待
排队等待
问题描述
有 n 个顾客需要服务,每个顾客有一个服务时间 和等待成本系数
。顾客的等待成本为:等待时间 × 等待成本系数。求一个服务顺序,使得所有顾客的总等待成本最小。
贪心策略
- 按照服务时间和等待成本系数的比值
升序排序
- 按照排序后的顺序依次服务顾客
正确性证明
假设最优解中存在相邻的两个顾客 i 和 j,且 。
交换这两个顾客的位置:
- i 的等待成本减少:
- j 的等待成本增加:
总成本变化:
由于 ,所以
因此交换后总成本增加,与最优解假设矛盾。
算法实现
class Solution {
public:
vector<int> minWaitingTime(vector<int>& times, vector<int>& costs) {
int n = times.size();
vector<pair<double, int>> ratios(n);
// 计算每个顾客的时间/成本比
for (int i = 0; i < n; i++) {
ratios[i] = {(double)times[i] / costs[i], i};
}
// 按比值升序排序
sort(ratios.begin(), ratios.end());
// 返回顾客的服务顺序
vector<int> order(n);
for (int i = 0; i < n; i++) {
order[i] = ratios[i].second;
}
return order;
}
};
class Solution {
public int[] minWaitingTime(int[] times, int[] costs) {
int n = times.length;
// 创建顾客索引数组
Integer[] indices = new Integer[n];
for (int i = 0; i < n; i++) {
indices[i] = i;
}
// 按时间/成本比升序排序
Arrays.sort(indices, (i, j) -> {
double ratio1 = (double)times[i] / costs[i];
double ratio2 = (double)times[j] / costs[j];
return Double.compare(ratio1, ratio2);
});
return Arrays.stream(indices).mapToInt(i -> i).toArray();
}
}
class Solution:
def minWaitingTime(self, times: List[int], costs: List[int]) -> List[int]:
n = len(times)
# 计算每个顾客的时间/成本比,并记录原始索引
ratios = [(times[i] / costs[i], i) for i in range(n)]
# 按比值升序排序
ratios.sort()
# 返回顾客的服务顺序
return [i for _, i in ratios]
时间复杂度分析
- 计算比值:
- 排序:
- 总时间复杂度:
- 空间复杂度:
应用场景
- 工厂生产调度
- CPU任务调度
- 银行柜台服务
- 医院就诊排序
- 打印任务队列
扩展问题
- 考虑服务优先级
- 添加截止时间约束
- 多服务窗口情况
- 动态到达的顾客
- 带预约的服务系统
注意事项
- 处理除法精度问题
- 考虑特殊输入(0值处理)
- 处理相等比值的情况
- 确保成本计算的准确性
- 注意整数溢出问题
牛客代码笔记-牛栋 文章被收录于专栏
汗牛充栋,学海无涯。<br/> 内含算法知识点讲解,以及牛客题库精选例题。<br/> 学习算法,从牛栋开始。