913.排序不等式--排队打水

原题: 

有 n 个人排队到 1 个水龙头处打水,第 i 个人装满水桶所需的时间是 ti,请问如何安排他们的打水顺序才能使所有人的等待时间之和最小?

输入格式

第一行包含整数 n。

第二行包含 n 个整数,其中第 i 个整数表示第 i 个人装满水桶所花费的时间 ti。

输出格式

输出一个整数,表示最小的等待时间之和。

数据范围

1≤n≤105,
1≤ti≤104

输入样例:

7
3 6 1 4 2 5 7
输出样例:

56
 

对题目中例子的分析:

 最后的56是怎么得来的?

要想时间最少,那么就要求打水时间越少的人排在越前面打水。所以我们先排序,最终打水顺序为:

1,2,3,4,5,6,7  他们分别需要等待的时间为:

1:等0分钟

2:等1分钟

3:等1+2分钟

......

7:等1+2+3+4+5+6分钟

所以等待时间总和为:

sum=0+1+(1+2)+(1+2+3)+...+(1+2+3+4+5+6)

法一(贪心+前缀和):

 代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N];
int s[N];
 
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    
    sort(a+1,a+n+1); // 因为下标是从1开始的,所以排序sort()函数也要相应地改一下
    
    for(int i=1;i<n;i++) // 循环条件不能写成 i<=n,因为这样会把最后一个人接水的时间也算上去,而实际上他接水的时间并不属于总的等待时间 
    {
        s[i]=s[i-1]+a[i];
    }
    
    long long int sum=0;
    for(int i=1;i<=n;i++) sum+=s[i];
    
    cout<<sum;
    return 0;
}


思路:

①输入,用数组存,注意下标从1开始,因为后面要用到前缀和,下标从1开始会更方便。

②用sort()函数对数组从小到大排序。

③求前缀和,s[i]=s[i-1]+a[i] 。(i从1开始)

④求时间和 sum+=s[i] 。

⑤输出 sum

法二(排序不等式):

 代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100005;
int main()
{
    int a[N];
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    sort(a, a + n);
    long long int sum = 0;
    for (int i = 0; i < n; i++)// 也可以换成 i<n-1 因为最后一项是 sum+=a[n-1]*0,加相当于不加,所以最后一项可以省略
    {
        sum += a[i] * (n - 1 - i);
    }
    cout << sum;
}

 思路:

从上面对题目例子的分析可以发现,实际上的总等待时间 sum 加了6次第一个人的打水时间,加了5次第二个的打水时间......,加了1次第六个人的打水时间,加了0次最后一个人的打水时间,所以可以推出公式:sum=a[1]*(n-1)+a[2]*(n-2)+a[3]*(n-3}+...+a[n-1]*1+a[n]*0

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值