1. 排队打水问题的贪心算法解析
1.1 问题描述与理解
排队打水问题是一个经典的贪心算法应用场景。题目描述为:有n个人需要到r个水龙头前打水,每个人打水所需的时间分别为t1,t2,...,tn(各不相等)。我们需要安排这些人的打水顺序,使得所有人打水的总花费时间最少。
这里的"总花费时间"指的是所有人等待时间(包括自己打水时间)的总和。例如,如果有3个人在1个水龙头前打水,所需时间分别为2、5、3分钟。如果按2、3、5的顺序打水,总花费时间为2+(2+3)+(2+3+5)=17分钟。
1.2 贪心策略的选择
对于单水龙头(r=1)的情况,最优策略很简单:让打水时间短的人先打水。这样可以让更多人尽快完成,减少长等待时间对总时间的影响。
对于多水龙头(r>1)的情况,我们需要扩展这个思路。正确的贪心策略是:
- 将所有人按打水时间从小到大排序
- 将当前打水时间最短的人分配到当前最早空闲的水龙头
这个策略可以形式化证明其最优性。关键在于:让短任务优先执行,可以最小化长任务对总时间的贡献。
1.3 算法实现详解
cpp复制#include<bits/stdc++.h>
using namespace std;
int main(){
int n,r,sum=0;
cin>>n>>r;
vector<int> a(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a.begin(),a.end()); // 按打水时间排序
vector<int> t(r,0); // 记录每个水龙头的当前结束时间
for(int i=0;i<n;i++){
int min_pos = 0;
for(int j=1;j<r;j++){ // 找出最早空闲的水龙头
if(t[j]<t[min_pos]) min_pos=j;
}
t[min_pos] += a[i]; // 分配当前最短任务
sum += t[min_pos]; // 累加总时间
}
cout<<sum
