问题描述
N个人要打水,有M个水龙头,第i个人打水所需时间为Ti,请安排一个合理的方案使得所有人
的等待时间之和尽量小。
输入格式
第一行两个正整数N M 接下来一行N个正整数Ti。
N,M<=1000,Ti<=1000
输出格式
最小的等待时间之和。(不需要输出具体的安排方案)
样例输入
7 3
3 6 1 4 2 5 7
样例输出
11
提示
一种最佳打水方案是,将N个人按照Ti从小到大的顺序依次分配到M个龙头打水。
例如样例中,Ti从小到大排序为1,2,3,4,5,6,7,将他们依次分配到3个龙头,则去龙头
一打水的为1,4,7;去龙头二打水的为2,5;去第三个龙头打水的为3,6。
第一个龙头打水的人总等待时间 = 0 + 1 + (1 + 4) = 6
第二个龙头打水的人总等待时间 = 0 + 2 = 2
第三个龙头打水的人总等待时间 = 0 + 3 = 3
所以总的等待时间 = 6 + 2 + 3 = 11
代码如下:
import java.util.Arrays;
import java.util.Scanner;
public class 打水问题 {
/**
* @param args
* 思路:这道题目我们需要求等的时间最少,那我们需要把接水时间长的人放到最后来接水,这样等的时间是最少的
* 1.先对用户输入的数据进行排序
* 2.然后 给他们进行分组,按照水龙头的个数来一排分几个,这个时候我们需要定义一个二维数组
* 3.最后来累加总的时间,(1)先来累加前a/b排需要等的总时间,当然第一排不需要等,这个时候我们需要进行累加前a/b排
* 人数等的总时间,(2)因为a/b还不能整除,所以肯定还剩的有人在最后一排,但是没有排满,那我们就应该再求一下最后一排人等的总时间
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
int arr []=new int[a]; //储存用户输入的一组数据
for (int i = 0; i <a; i++) {
arr[i]=sc.nextInt();
}
Arrays.sort(arr); //从小到大排序
int row = (a/b)+1; //定义二维数组的行数
int arr1[][]=new int[row][b]; //定义一个二维数组来对用户输入的数据进行按顺序分配成row行b列
int s = 0; //定义变量用来计数,
for (int i = 0; i <row; i++) {
for (int j = 0; j <b; j++) {
if (s<a) { //防止越界
arr1[i][j]=arr[s];
s++;
}
}
}
//接下来就是这么累加总的时间,
int sum = 0; //用来存储最短的时间总和
for (int t = 1; t <a/b; t++) { //第一层循环用来判断循环次数
for (int i = 0; i <t; i++) {
for (int j = 0; j <b; j++) {
sum+=arr1[i][j]; //对接水的时间进行累加
}
}
}
//前面的循环只累加整行的数据,下面的循环是来累加a%b后剩下的人数应该等多长时间
for (int i = 0; i <row-1; i++) {
for (int j = 0; j <a%b; j++) {
sum+=arr1[i][j]; //因为后面的人数等的时间应该要把前面所有人等的时间全部加起来,所以我们只要在之前的sum基础上继续累加就可以了
}
}
System.out.println(sum); //最后输出总时间
}
}
程序调试结果如下:
48 8
38 23 41 16 42 15 22 15 8 17 39 19 5 16 23 44 30 5 26 14 44 21 2 31 40 18 6 1 48
5 15 48 25 42 21 30 24 12 26 14 12 35 37 45 46 27 18 39
结果:1887