一、基础版排队打水

【题目描述】

学校里有一个水房,水房里一共装有m 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为1。

现在有n 名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从1到n 编号,i号同学的接水量为wi。接水开始时,1到m 号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学j完成其接水量要求wj后,下一名排队等候接水的同学k马上接替j 同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即j 同学第x 秒结束时完成接水,则k同学第x+1 秒立刻开始接水。若当前接水人数n′不足m,则只有n′个龙头供水,其它m−n′个龙头关闭。

现在给出n名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。

详细描述及解法请点击这里


二、进阶版排队打水

【题目描述】

有n个人排队到r个水龙头去打水,他们装满水桶的时间t1,t2,…,tn为整数且各不相等,应如何安排他们的打水顺序才能使他们总共花费的时间最少?

【输入描述】

第一行n,r (n<=500,r<=75)
第二行为n个人打水所用的时间Ti (Ti<=100);

【输出描述】

最少花费时间

【样例输入1】

3 2
1 2 3

【样例输出1】

7

【样例输入2】

4 2
2 6 4 5

【样例输出2】

23

【题目分析】

(1)题目描述比较坑,有一个非常重要的点没有告知:

接水的总时间=每个人接水的时间之和
每个人接水花费的时间=每个人接水的时间+等待时间


(2)我们是已经知道了每个人的接水的时间,现在的主要目的是如何给他们排队,让总时间最少。

样例1的解释,一共3个人,2个水龙头。
策略一:先让花费时间最少的两个人先去。

这里第一名同学需要花费了1分钟,第二名同学需要花费了2分钟。此时第三位同学还没有安排,但是已知第三名同学接水需要3分钟,如果第三位同学在2号水龙头,那么他将花费3+2(2是他在2号水龙头等待的时间),比他在1号水龙头额外多花1分钟。显然,3号同学应该在1号水龙头后等待接水,这样总体接水的时间是最少的。
1+2+(3+1)=7

策略二:让花费时间的多的先去。

我们让花费时间最多的两位同学先去,这个时候,最后一位同学有如果在2号水龙头,他将花费2+1分钟。如果去1号水龙头,他将花3+1分钟。显然,在策略二中最少的排队接水时间应该是3+2+(2+1)=8分钟。

综上来说,对于样例1,应该选择策略一,将需要排队人总是安排到当前水龙头花费时间最少的那个。

同样,样例2,也可以有类似的解释。

(3)我们要求一个总时间,某个人的花费时间是排在当前这个水龙头的总时间+ 这个人接水的时间。


【参考代码1】

#include<cstdio>
#include <algorithm>
using namespace std;
int water[501];  //学生接水时间数组
int taps[501]= {0}; //水龙头
int main() {
	int n,r;
	int sum=0;
	scanf("%d%d",&n,&r);
	int i;
	for(i=0; i<n; i++)
		scanf("%d",&water[i]);
	sort(water,water+n); //让接水时间短的先接水
	
	for(i=0; i<n; i++) { //每次循环一个人 
		sort(taps,taps+r); //r水龙头,找出当前时间哪个水龙头接水时间最短 
		sum+=taps[0]+water[i]; //taps[0]肯定是接水时间最短的那个队的总时间,让当前这个人去这个队 
		taps[0]+=water[i]; //把当前这个人接水时间加到当前水龙头里 
	}
	printf("%d\n",sum);
	return 0;
}

对于测试数据

4 2
2 6 4 5

的过程表示是

排队打水的数学推导过程

要让平均排队时间最小,就要让打水快的人往前排

证:

设有n个人打水,每个人的打水时间分别为 x_1,x_2,x_2,…,x_nx1​,x2​,x2​,…,xn

则打水时间总和为x_1*(n-1)+x_2*(n-2)+…+x_{n-1}*1+x_n*0x1​∗(n−1)+x2​∗(n−2)+…+xn−1​∗1+xn​∗0

要让打水总时间最小,就要让x_1<x_2<…<x_nx1​<x2​<…<xn

所以我们可得

1.排序,对输入进行排序,使其变成x_1<x_2<…<x_nx1​<x2​<…<xn这个序列

2.累加时间,如果用x_1*(n-1)+…+x_{n-1}*1+x_n*0x1​∗(n1)+…+xn1​∗1+xn​∗0会比较麻烦,我们换一个方式,x_0=0x0​=0 我们求x_0+(x_0+x_1)+…+(x_0+x_2+…+x_{n-1})x0​+(x0​+x1​)+…+(x0​+x2​+…+xn1​)

3.把加完的时间除以n,再把x_1,x_2,…,x_nx1​,x2​,…,xn和时间输出

总等待时间:t1+(t1+t2)+(t1+t2+t3)+……+(t1+t2+t3+……+tn)

所以要把接水时间较少的放在前面

三、相关题目

【题目描述】

有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

返回目录:算法


分类: 算法