小七首博!
本菜小声bb
- 小七,崇拜类人猿
- 近两天小七人生第一次被技术面、机试的爸爸们殴打之后,打算变成爸爸那样的人
- 于是乎有了这第一篇分享:关于昨晚做的华为机试-软件类-题3;当时没想出来,回去以后继续想了十几分钟有了一个大概的思路,到今天上午整理清思路来分享辽!
- 初来乍到,应该不晚!
情景带入
华父购得咖啡机若干,宾客纷至沓来,毕竟在打码闲暇时小酌一杯,实为人生一大乐事
这时,华父却说:
“既然要在我的地盘上撒野,就得按照我的方式来撒!”
具体细则如下:
- 每台咖啡器有自己的cook time
- 每台咖啡机一次只能做一杯咖啡,
垃圾 - 喝咖啡的过程是透明的(秒喝)
- 喝了咖啡必须洗杯子不然会很臭,
讲究 - 选择洗杯机洗杯子(时间x),或者神奇的等待咖啡残渣自己挥发(时间y)
- 我只有钱买一台洗杯机(多人需要排队等待)
题目要求
每个华父手下有小弟n人,求这n个小弟均品尝一番咖啡之后的最少时间 :P
并且把上述“华父买咖啡机,立破规矩”的过程复制若干次:
- 输入第一行是指复制的次数(case数目)
- 第二行开始,每两行为一组
- 每组第一行表示该case下面的n m x y参数, 第二行表示这批咖啡机每台的工作时间
- 输出每个case的最少时间,换行 。
输入范例1
1
1 1 1 1
10
输出范例1
11
输入范例2
2
2 2 1 1
10 8
1 1 1 1
10
输出范例2
11
11
解题思路
· 昨晚在线答题的时候
比较输入的验è¯ç 和实际生æˆçš„验è¯ç 是å¦ç›¸å
return null
“图书馆思考了俩小时了,该吃宵夜了”
· 回去经过十几分钟的思考
干他!
- 每个case的n m x y 的配置抽象成为一个Coffee对象,计算该对象所对应的最短时间
- 以小弟的视角切入,每个小弟面临两个选择:
- 用哪一台咖啡机可以最快开始享受人生?
得到该人等待咖啡机的时间和煮咖啡的时间 - 等杯子自己洗还是去洗杯子?
得到该人等待洗杯器的时间和洗杯子的时间(自己洗就不用等待洗杯器)
- 用哪一台咖啡机可以最快开始享受人生?
如何确定这两个选择?
- 从时间0开始,到选择了一台咖啡机并且时间最短的那台咖啡机,具体如下
- initial 假设初始选择第0台咖啡机, minTime = wait(0) + cook(0), min = 0
- for i from 1 to m-1 咖啡机:
if 某一台咖啡机所用的时间+等待时间 cook(i) + wait(i)<目前所选的咖啡机 cook(min) + wait(min) :
min = i, minTime = wait(i) + cook(i);
update 该小弟等待咖啡机的时间以及煮完咖啡的时间endTime
- 从时间最短的咖啡机工作完之后,洗杯机才进入自己的时间线,所以洗杯机开始时间记为耗时最短的咖啡机的工作时间:begin=min{cook(i)},具体如下:
- initial 假设等待洗杯机的时间wait:
if begin+使用洗杯机的总人数*洗杯机的工作时间<该人煮完咖啡的时间,说明该人在煮完咖啡之前,洗杯机就空闲了,不用等待
wait=0;
else 还要等待洗杯机
wait=begin+洗杯机工作人数*洗杯机的工作时间-该人煮完咖啡的时间; - 决定等待洗杯机洗杯子还是自己挥发?
if wait+x<y:等待洗杯机
endTime += wait + x;
使用洗杯机的总人数++;
else 等待挥发
endTime += y;
- initial 假设等待洗杯机的时间wait:
- 每个人做完选择之后,最短时间就是最大的endTime
- ** Done.**
两条时间线如何合并在一起
假设现在有3台咖啡机,4个小弟;画个小图解释一下:
首先先把两个等待时间线完全分开:
为了简便,就用甘特图简单展示一下情况,同种颜色的小弟,表示他们使用同一种咖啡机
类似地,对于洗杯机有:
可以看出,小弟4和小弟6都没有使用洗杯机,而是佛等残渣自己挥发
到这里,基本can tell at a glance——
要是把两个图合在一起,最后那个时间点不就是要求的东西了吗!!
那么把等待洗杯机和等待咖啡机在哪个时间片黏在一起呢?
-
简单分析如下:
- 图一的时间从0开始即有意义,因为先做咖啡毋庸置疑;
- 图二等待洗杯机一定要有人喝完咖啡才有意义,所以时间从第一个人喝完咖啡开始
-
回到上图就是图一中的小弟1结束时刻和下图的小弟1的开始时刻拼在一起,就得到完整的一张图(
虽然还没结束,但可以开心一下) - 呵,找到了。
那么之后的选择和调整,就参见之前的算法说明,就可以知道黏在一起的时候,同一个小弟的两个框之间距离是多少(wait的计算),以及如何在佛等干和排队洗杯机之间做出抉择,OVER.
代码演示
public class MinTime {
public static void main(String[] args) throws IOException{
int count, n, m, x, y;
int[] t;
Scanner sc = new Scanner(System.in);
count = sc.nextInt();
MinTime mt = new HelloWorld();
//因为此时调用main方法的时候,main是静态方法,随着类型的加载初始化,但是如果需要使用内部类Coffee对象,需要用外部类的对象
Coffee s ;//内部类对象
for(int i = 0; i<count; i++) {
n = sc.nextInt();
m = sc.nextInt();
x = sc.nextInt();
y = sc.nextInt();
t = new int[m];
for(int j= 0; j<m; j++)
t[j] = sc.nextInt();
s = mt.new Coffee(n, m, x, y, t); //用外部类对象初始化内部类对象
System.out.println(s.totalTime());
}
}
class Coffee{
int n, m, x, y, wStatus; //wStatus对应目前使用了洗杯机的总人数
int[] cTime, cStatus, bTime, eTime; //分别是每个咖啡机煮咖啡的时间,每个咖啡机的使用人数,每个人的开始时间(鸡肋),每个人的结束时间
Coffee(int n, int m, int x, int y, int[] t){ //初始化所有变量
this.n = n;
this.m = m;
this.x = x;
this.y = y;
cTime = new int[m];
for(int k=0; k<m; k++)
cTime[k] = t[k];
cStatus = new int[m];
bTime = new int[n];
eTime = new int[n];
wStatus = 0;
}
void choose1(int i){ //选择咖啡机
int minCoffee = 0; //假设0号咖啡机耗时最短
int min = cTime[0] * (cStatus[0] + 1);//如果我选0号咖啡机,直到煮咖啡结束的时间花费
for(int j=1; j<m; j++) {
if(cTime[j] * (cStatus[j] + 1) < min) { //更新最短时间咖啡机选择(等待时间+使用时间)
min = cTime[j] * (cStatus[j] + 1);
minCoffee = j;
}
}
bTime[i] = cTime[minCoffee] * cStatus[minCoffee]; //开始时间
eTime[i] = bTime[i] + cTime[minCoffee]; //结束时间
cStatus[minCoffee]++; //使用咖啡机人数++
}
void choose2(int i) {
//从0开始计数,目前需要等待的时间
int wait = wStatus*x + eTime[0] - eTime[i] < 0 ? 0: wStatus*x + eTime[0] - eTime[i];
if(wait+x<y) {//如果等待时间加上洗杯子时间比自己挥发块
wStatus++; //洗杯机使用人数++
eTime[i]+=x;
}
else
eTime[i]+=y;
}
int totalTime() { //最短时间计算
for(int i=0; i<n; i++) {
choose1(i);
}
for(int i=0; i<n; i++) {
choose2(i);
}
//Arrays.sort(eTime); 最后那个人一定是最后完成的
//其实上面的choose的执行可以每个人先后执行choose1 choose2
return eTime[n-1];
}
}
}
写在最后
- 个人认为此题的核心就是时间线的记录,当时完全没有想清楚怎么记录时间线,然后晚上回去继续想了一下就大概确定了这个思路,根据相对等待时间来决定绝对时间
- 另一点是咖啡机和洗杯机两者的时间怎么重合起来,重点要想清楚洗杯机的时间要从第一个人完成咖啡制作之后(第一个人一定选择最短工作时间的咖啡机)才生效,等待时间的比较也是一个点
- 如果都是顺序遍历每一个人的话,最后的时间不用排序,最后一个人一定是最后一个完成的,因此只用拿最后一个人的endTime即可
- 最开始看到这个问题的时候,会想到os的资源抢占,排队等待之类,但个人实在不知道如何用多线程来实现,于是想了这样一个静态的办法
- 有错误欢迎指正讨论