题目描述
有 n个人在一个水龙头前排队接水,假如每个人接水的时间为Ti,请编程找出这 n 个人排队的一种顺序,使得 n 个人的平均等待时间最小。
输入格式
第一行为一个整数 n。
第二行 n 个整数,第 i 个整数Ti 表示第 i 个人的等待时间 Ti。
输出格式
输出文件有两行,第一行为一种平均时间最短的排队顺序;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。
输入输出样例
输入
10 56 12 1 99 1000 234 33 55 99 812
输出
3 2 7 8 1 4 9 6 10 5 291.90
说明/提示
n≤1000,ti≤10^6,不保证 ti 不重复。
当 ti 重复时,按照输入顺序即可(sort 是可以的)
这道题目的标签是贪心,那么这道题目必然是使用贪心做。这里用一句话解释贪心:在每一时间下做出当前的最优解。这道题目后续有提示,可以使用sort。
这里简单介绍一下sort,这是c++中的一个函数,用来进行排序的,函数参数为首地址,尾地址,比较条件,这里如果只学习了c语言的情况下可以手写一个排序。使用sort排序的时间复杂度为nlogn。
现在开始进行题目的分析
这道题的要求是让N个人的平均等待时间最短,这里我们可以思考一下,如果我们随意进行排序,那么留在最前面的的人接水就需要后面所有人去等他接水,然后第二个人再接水。这样下来了就会发现,其实当前面的人接水所花费的时间越短,后面的人等待的时间就越短,所以我们能得出这道题目的解题关键,所花时间短的人应该排在前面,时间长的人排在后面。
这样的想法本身没错了,但是如果我们直接进行排序的话,那么就自然会打乱这些人的编号,到后面就无法输出了。这里我们可以想到,使用结构体,储存每一个人的编号和打水所花费的时间。
sort(peo, peo + n, cmp);
for (int i = 0; i < n; i++) {
cout << peo[i].n << " ";
sum += peo[i].t * (n - i-1);
}
现在开始coding
struct people {
int n;
int t;
};
创造一个名为people(人)的结构体
这是比较条件,如果只学习了c语言可以写一个排序,这里我就不过多赘述了
bool cmp(people a, people b) {
return a.t < b.t;
}
接收条件,sum用它来计算所有人等待的时间
for (int i = 0; i < n; i++) {
cout << peo[i].n << " ";
sum += peo[i].t * (n - i-1);
}
这里开始根据所写的判断条件进行排序,并且计算总的等待时间。这里可以简单说明一下sum。假设总共10人,第一个人打水,后面9个人就要跟着等待,因为数组的下标是从0开始的,所以这里这个人的编号为i+1,后面所有正在等待的人数就为n-1-i。到这里这个简单的贪心算法题就差不多结束了,后面将我写的代码放到最后面,不会写的可以参照最后放出的代码,根据此进行书写,不过还是希望不要直接抄,理解思路之后自己试一试。
#include<iostream>
#include<algorithm>
#include<cmath>
#include <iomanip>
#include<string>
#include<vector>
#include<cstdio>
using namespace std;
struct people {
int n;
int t;
};
struct people peo[1000];
bool cmp(people a, people b) {
return a.t < b.t;
}
int main() {
int n;
double sum = 0;
cin >> n;
for (int i = 0; i < n; i++) {
peo[i].n = i + 1;
cin >> peo[i].t ;
}
sort(peo, peo + n, cmp);
for (int i = 0; i < n; i++) {
cout << peo[i].n << " ";
sum += peo[i].t * (n - i-1);
}
cout << endl;
printf("%.2f", sum/n);
return 0;
}