洛谷-排队接水(P1223)

博客皆个人学习过程中整理,如有问题,欢迎大家指正。
本文链接: https://blog.csdn.net/qq_42017331/article/details/102057818

题目描述:

有n个人在一个水龙头前排队接水,假如每个人接水的时间为Ti,请编程找出这n个人排队的一种顺序,使得n个人的平均等待时间最小。
输入格式 输入文件共两行,第一行为n;第二行分别表示第1个人到第n个人每人的接水时间T1,T2,…,Tn,每个数据之间有1个空格。

输出格式:

输出文件有两行,第一行为一种排队顺序,即1到n的一种排列;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。

输入输出样例 输入 #1

10
56 12 1 99 1000 234 33 55 99 812

输出 #1

3 2 7 8 1 4 9 6 10 5
291.90

说明/提示 n<=1000
ti<=1e6,不保证ti不重复
当ti重复时,按照输入顺序即可(sort是可以的)

问题分析:

本题类似进程调度里的最短作业优先算法。N个人接水,类似就绪队列中的进程,等待使用CPU。平均等待时间最小,即平均周转时间最小。不妨以操作系统的角度求解本问题。
回顾下周转时间:即从进程提交开始,到进程运行结束的这段时间。平均周转时间呢,即N个进程从被提交到结束的平均时间。
最段作业优先算法,每次选取进程运行时间最少的开始执行。该算法典型的贪心算法,每次选取运行时间最短的,毫无疑问,最终结果一定是最优解(每次选取时间最短的优先运行,即保证其他进程的周转时间相对较短)。

算法步骤:

  1. 对运行时间进行排序,目的是保证每个进程的周转时间最短(即每个人的等待时间最短)。
  2. 周转时间的计算,根据周转时间定义得知:我的周转时间包括前边的各进程周转时间(第N个人打水时间,包括前N-1个人的时间)
  3. 各进程的周转时间相加,再做一次平均运算,即最终结果。

代码示例:

#include<cstdio>
#include<algorithm>
using namespace std;

struct Person{
 	int num;
 	int time;
}que[1010]; 

bool cmp(Person x, Person y){
 	return x.time < y.time;
}

int main(){
 	int n;
 	long sum = 0;
  	scanf("%d", &n);
 	for(int i = 0; i < n; i++){
  		scanf("%d", &que[i].time);
  		que[i].num = i+1;
 	}
 	sort(que, que+n, cmp);
 	for(int i = 0; i < n; i++){
  		printf("%d ", que[i].num);
  		sum += (n-i-1) * que[i].time;
 	}
 	printf("\n%.2lf", sum / (n * 1.0));
 	return 0;
} 

虽然运行时间是整数, 但是计算总时间时需要注意整型范围溢出,因此不妨将总时间的数值类型开的更大一点。

总结:

求解本问题时,一直以最短作业优先算法的思维做这题。但是测试一直不过。原因在于,本题不需要将自己的执行时间计入在总时间里(自己在打水时间没有被算入)。

猜你喜欢

转载自blog.csdn.net/qq_42017331/article/details/102057818