排队打水(贪心)
题目:排队打水(贪心)
题意:
有 n 个人排队到 1 个水龙头处打水,第 i 个人装满水桶所需的时间是 ti,请问如何安排他们的打水顺序才能使所有人的等待时间之和最小?
输入格式
第一行包含整数 n。
第二行包含 n 个整数,其中第 i 个整数表示第 i 个人装满水桶所花费的时间 ti。
输出格式
输出一个整数,表示最小的等待时间之和。
数据范围
1≤n≤1e5,
1≤ti≤1e4
输入样例:
7
3 6 1 4 2 5 7
输出样例:
56
样例解释:
按 1 2 3 4 5 6 7的顺序排列,则等待的时间是1 + 3 + 6 + 10 + 15 + 21 = 56。
题目分析:贪心,设排列的顺序为a1, a2, a3, ......, an。则a1要被等n – 1次,a2要被等n – 2次, ...... ,an要被等0次。即ai要被等n – i次,所以排越前面权重越大。
解题步骤:
- 将所有人按装水时间ti从小到大排序。
- 累加每个人前面所有人的装水时间。
贪心策略证明:
- 设贪心得出的答案是cnt,本题的正确答案是ans。
- 由于本题的答案ans是所有方案的最小值,所以必有ans <= cnt。
- 设在正确答案中有排列顺序有i < j且ai > aj,则我们可以交换ai和aj的位置,交换后,数值小的点权重变大,数值大的点权重变小,且ai和aj的权重改变量是相等的,所以交换后能够得到更小的答案。故有cnt <= ans。
- 由于ans <= cnt且cnt <= ans,得cnt = ans。
AC代码:
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
int a[N], n;
void solve(){
scanf("%d", &n);
for(int i = 1;i <= n;i++) scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
ll cnt = 0, res = 0;
for(int i = 1;i <= n;i++){
if(i >= 1) res += cnt;
cnt += a[i];
}
printf("%lld\n", res);
}
int main(){
solve();
return 0;
}
时间复杂度:O(NlogN)。
空间复杂度:O(N)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具