喝咖啡
题目描述
2019.4.3华为笔试题目:喝咖啡
有m个咖啡机,n个人。一个清洗机。
有n个人要喝咖啡,喝完之后要清洗杯子。m个咖啡机做咖啡的时间各不相同,分别为V1、V2...Vm。清洗机清洗杯子所用时间为x。此外,如果一个人喝完的杯子y时间内没清洗,里面的残存的咖啡会挥发掉,相当于清洗完毕。
问所有人喝完咖啡+清洗完杯子需要的最短时间(忽略喝咖啡需要的时间)。
输入:
第一行:一个数字T,表示T组测试数据
第二行:第一组测试数据的 n m x y
第三行:第一组测试数据m个咖啡机的工作效率 V1 V2 。。。Vm
第四行:第二组。。。。以此类推
总的思路:
1.咖啡机可以根据人数和各个咖啡机效率分配好,不需要模拟,分配的函数是personCofe(int[] listCofe,int n,int m),具体看下 面代码
2.假设的前提是:如果所有人制作完成咖啡之后,洗碗和晾干的时间唯一需要考虑的是制咖啡最后两个人的时间差。
时间差如果比洗碗时间短的话,需要增加最后一个人的洗碗时间加上倒数第一人洗碗减去等倒数第二人的时间
3.如果最后所有人制作完成咖啡后,按照最短时间规划洗碗或者晾干方案,导致洗碗排队的人超过了1人的话,下面代码出 bug,消除bug貌似挺复杂的,有办法更正的大佬可以解决一下把
4.编程菜鸟,第一次发,如有错误,欢迎各位批评指正!
代码实现:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class Main02 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = Integer.parseInt(sc.nextLine());
// System.out.println(T);
// 下面先将所有数据读出来,将每一个String装进ArrayList中,中间有空格,前四个是nmxy后面是洗碗时间
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < T; i++) {
StringBuilder sb = new StringBuilder();
sb.append(sc.nextLine());
sb.append(" ");
sb.append(sc.nextLine());
list.add(sb.toString().trim());
}
// System.out.println(list); //上面用例1输出 [1 1 1 1 10 , 2 2 1 1 10 8
for (String ss : list) {
String[] str = ss.split(" ");
int len = str.length;
int[] irr = new int[len];
for (int i = 0; i < len; i++) {
irr[i] = Integer.parseInt(str[i]);
}
// System.out.println(Arrays.toString(irr));
// 下面分开他们的赋值,前四个先变成nmxy
int n = irr[0];
int m = irr[1];
int x = irr[2];
int y = irr[3];
ArrayList<Integer> list2 = new ArrayList<>();
for (int i = 4; i < len; i++) {
list2.add(irr[i]);
}
// 先取出制作咖啡时间
// 下面将list2装进数组里
int[] iCofe = new int[m];
for (int i = 0; i < m; i++) {
iCofe[i] = list2.get(i);
}
// 根据总人数,取出分配方案
Arrays.sort(iCofe);
int[] personCofe = personCofe(iCofe, n, m);
// 根据分配方案,求出制作咖啡完成时间,并且取出最后一人和倒数第二人差时间
int timedif = 0;
int timeCofe = 0;
for (int i = 0; i < m; i++) {
int temp = personCofe[i] * iCofe[i];
if (temp > timeCofe) {
timedif = temp - timeCofe;
timeCofe = temp;
}
}
// System.out.println(timeCofe);
// 下面计算洗杯子或者挥发时间
int timeCup = 0;
// 如果洗碗时间比晾干时间还长,直接全部晾干
if (x >= y) {
timeCup = y;
} else {
// 看看差值到底比洗碗时间长短
if (timedif > x) {
timeCup = x;
} else {
if (2 * x - timedif > y) {
timeCup = y;
} else {
timeCup = 2 * x - timedif;
}
}
}
System.out.println(timeCofe + timeCup);
}
}
// 直接传入从大到小排好序的机器
public static int[] personCofe(int[] listCofe, int n, int m) {
int[] personCofe = new int[m];
personCofe[0] = n;
// 如果当前位置上的时间乘以当前位置排队人数,大于下一位置排队人数加一乘以下一位置的值,也就是需要发生进位了!进位一下
if (m == 1) {
return personCofe;
}
while (listCofe[0] * personCofe[0] >= listCofe[1] * (personCofe[1] + 1)) {
// 每次最低位要进位,所有其他位置都需要检查是否需要进位
personCofe[1]++;
personCofe[0]--;
for (int i = 1; i < m - 1; i++) {
if (listCofe[i] * personCofe[i] >= listCofe[i + 1] * (personCofe[i + 1] + 1)) {
personCofe[i + 1]++;
personCofe[i]--;
}
}
}
// 下面注释消除可以直接输出每台咖啡机分配的人数,顺序是咖啡机效率从小到大
// System.out.println(Arrays.toString(personCofe));
return personCofe;
}
}