题意
有 nnn 个人在一个水龙头前排队接水,假如每个人接水的时间为 TiT_iTi,请编程找出这 nnn 个人排队的一种顺序,使得 nnn 个人的平均等待时间最小。
输入格式
第一行为一个整数 nnn。
第二行 nnn 个整数,第 iii 个整数 TiT_iTi 表示第 iii 个人的接水时间 TiT_iTi。
输出格式
输出文件有两行,第一行为一种平均时间最短的排队顺序;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。
说明/提示
1≤n≤10001\le n \leq 10001≤n≤1000,1≤ti≤1061\le t_i \leq 10^61≤ti≤106,不保证 tit_iti 不重复。
思路
容易发现时间小的放前面更容易让平均排队时间变短,理由如下:
假设存在一种最优的方法,且满足存在 1≤i<j≤n1 \leq i < j \leq n1≤i<j≤n 且 Ti>TjT_i > T_jTi>Tj。
交换 (i,j)(i,j)(i,j) ,第 i+1i+1i+1 到第 j−1j - 1j−1 个人都少花了 Ti−TjT_i - T_jTi−Tj 分钟,第 iii 个人多花了 Σk=i+1jTi\Sigma^{j}_{k = i+1}{T_i}Σk=i+1jTi 分钟,第 jjj 人少用 Σk=ij−1Ti\Sigma^{j - 1}_{k = i}{T_i}Σk=ij−1Ti 分钟,总共比之前少用 (j−i)(Ti−Tj)(j - i)(T_i - T_j)(j−i)(Ti−Tj) 分钟,与原序列最优矛盾。故最优的序列一定是按照 TTT 从小到大排序的。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
struct node{
int id;
double T;
friend bool operator <(node x,node y) {
if(x.T != y.T) return x.T < y.T;
return x.id < y.id;
}
}people[1005];
double Time;
signed main() {
scanf("%lld",&n);
for(int i = 1;i <= n;i++) {
cin >>people[i].T;
people[i].id = i;
}
sort(people + 1,people + n + 1);
for(int i = 1;i <= n;i++) {
printf("%lld ",people[i].id);
Time += people[i - 1].T;
people[i].T += people[i - 1].T;
}
printf("\n%.2lf\n",Time / n);
return 0;
}