题目描述
张三要去外地出差,需要做核酸,需要在指定时间点前做完核酸,请帮他找到满足条件的核酸检测点。
- 给出一组核酸检测点的距离和每个核酸检测点当前的人数;
- 给出张三要去做核酸的出发时间出发时间是10分钟的倍数,同时给出张三做核酸的最晚结束时间;
- 题目中给出的距离是整数,单位是公里,时间1分钟为一基本单位;
去找核酸点时,有如下的限制:
- 去往核酸点的路上,每公里距离花费时间10分钟,费用是10元;
- 核酸点每检测一个人的时间花费是1分钟;
- 每个核酸点工作时间都是8点到20点中间不休息,核酸点准时工作,早到、晚到都不检测;
- 核酸检测结果可立刻知道;
- 在张三去某个核酸点的路上花费的时间内,此核酸检测点的人数是动态变化的,变化规则是:
– 在非核酸检测时间内,没有人排排队
– 8点-10点每分钟增加3人
– 12点-14点每分钟增加10人
– 18点-20点每分钟增加20人
– 其他时间每5分钟增加1人。
要求将所有满足条件的核酸检测点按照优选规则排序列出:优选规则:
- 花费时间最少的核酸检测点排在前面。
- 花费时间一样.花费费用最少的核酸检测点排在前面.
- 时间和费用一样,则ID值最小的排在前面
输入描述
H1 M1
H2 M2
N
ID1 D1 C1
ID2 D2 C2
…
IDn Dn Cn
解释
H1:当前时间的小时数
M1:当前时间的分钟数
H2:指定完成核算时间的小时数
M2:指定完成核算时间的分钟数
N:所有核酸检测点个数
ID1:核酸点的ID值。
D1:核酸检测点距离张三的距离
C1:核酸检测点当前检测的人数
输出描述
N
l1 T1 M1
12 T2 M2
输出解释
N:满足要求的核酸检测点个数
ln:选择后的核酸检测点ID
Tn:做完核酸花费的总时间(分钟)
Mn:去该核算点花费的费用
题解
java版本
import java.util.*;
public class NucleicAcidPlace {
public static void main(String[] args) {
// 当前时间的小时数
int h1 = 10;
// 当前时间的分钟数
int m1 = 30;
// 指定完成核算时间的小时数
int h2 = 14;
// 指定完成核算时间的分钟数
int m2 = 50;
// 所有核酸检测点个数
int n = 3;
// [ 核酸点的ID值 核酸检测点距离张三的距离 核酸检测点当前检测的人数 ]
int[][] nucleicAcidLocations = new int[][]{{1, 10, 19}, {2, 8, 20}, {3, 21, 3}};
printResult(h1, m1, h2, m2, n, nucleicAcidLocations);
}
private static void printResult(int h1, int m1, int h2, int m2, int n, int[][] nucleicAcidLocations) {
// 起始时间,单位分钟
int startTime = h1 * 60 + m1;
// 期望张三做核酸的结束时间,注意不能早于8点,不能晚于20点
int exceptEndTime = Math.min(h2 * 60 + m2, 20 * 60);
/**
* 核酸点每检测一个人的时间花费是1分钟
* 8点-10点每分钟增加3人, 出去1个人,相当于 8点~10点,每分钟增加2人
* 其他时间每5分钟增加1人 出去1个人 10点~12点,相当于每分钟减少0.8人
* 12点-14点每分钟增加10人,出去1个人 ,12~14点,相当于每分钟增加9人
* 其他时间每5分钟增加1人 出去1个人 14~18点,相当于每分钟减少0.8人
* 18点-20点每分钟增加20人 出去1个人 相当于18~20点,每分钟增加19人
*/
double[][] times = new double[][]{{8 * 60, 10 * 60, 2}, {10 * 60, 12 * 60, -0.8}, {12 * 60, 14 * 60, 9}, {14 * 60, 18 * 60, -0.8}, {18 * 60, 20 * 60, 19}};
int len = nucleicAcidLocations.length;
List<int[]> tempList = new ArrayList<>();
for (int i = 0; i < len; i++) {
int[] singleLocation = getSingleLocation(nucleicAcidLocations[i], startTime, exceptEndTime, times, n);
Optional.ofNullable(singleLocation).ifPresent(tempList::add);
}
int newLen = tempList.size();
int[][] result = new int[newLen][nucleicAcidLocations[0].length];
for (int i = 0; i < newLen; i++) {
result[i] = tempList.get(i);
}
System.out.println(result.length);
Arrays.sort(result, (o1, o2) -> {
if (o1[1] == o2[1]) {
if (o1[2] == o2[2]) {
return o1[0] - o2[0];
}
return o1[2] - o2[2];
}
return o1[1] - o2[1];
});
System.out.println(Arrays.deepToString(result));
}
private static int[] getSingleLocation(int[] nucleicAcidLocation, int startTime, int exceptEndTime, double[][] times, int n) {
// 核酸点id
int Acid = nucleicAcidLocation[0];
// 核酸点和张三的距离
int distance = nucleicAcidLocation[1];
// 核酸点在张三出发时已有的人数
int wait = nucleicAcidLocation[2];
// 每公里距离花费时间10分钟,费用是10元
int arrived = startTime + distance * 10;
// 8点之前到
if (arrived < 8 * 60) {
// 到达时间就是8点,排在初始人数后面
arrived = 8 * 60;
// 选择后的核酸检测点ID 做完核酸花费的总时间(分钟) 去该核算点花费的费用
return new int[]{Acid, arrived - startTime + wait, distance * 10};
}
// 算开始时间
// 到达时间。然后取交集。在加上增速
int e1 = arrived;
for (double[] time : times) {
double s2 = time[0];
double e2 = time[1];
double changePerMin = time[2];
double t = intersection(startTime, e1, s2, e2);
// 存在交叉的区间
if (t > 0) {
wait += t * changePerMin;
// 要注意,因为存在的人数减少的情况,所以要跟0取max
wait = Math.max(0, wait);
}
}
if (startTime + (arrived - startTime + wait) > exceptEndTime) {
return null;
}
return new int[]{Acid, arrived - startTime + wait, distance * 10};
}
private static double intersection(double s1, double e1, double s2, double e2) {
// s2在 s1和e1 之间[s1, e1)。相交的部分就是
if (s1 <= s2 && s2 < e1) {
// 开始于s2,结束看e1 和 e2 的最小值
return Math.min(e1, e2) - s2;
}
// s1在[s2, e2)之间
if (s2 <= s1 && s1 < e2) {
return Math.min(e1, e2) - s1;
}
return 0;
}
}
python版本
def intersection(s1, e1, s2, e2):
# s2在 s1和e1 之间[s1, e1)。相交的部分就是
if s1 <= s2 <e1: # 开始于s2,结束看e1 和 e2 的最小值。
return min(e1, e2) - s2
# s1在[s2, e2)之间
if s2 <= s1 <e2:
return min(e1, e2) - s1
# 都满足不了
return 0
def result():
start = h1 * 60 + m1 # 把时间算出来
except_end = min(h2*60+m2, 20 * 60) # 不能早于8点,不能晚于20点
# 核酸点每检测一个人的时间花费是1分钟
# 8点-10点每分钟增加3人, 出去1个人,相当于 8点~10点,每分钟增加2人
# 其他时间每5分钟增加1人 出去1个人 10点~12点,相当于每分钟减少0.8人
# 12点-14点每分钟增加10人,出去1个人 ,12~14点,相当于每分钟增加9人
# 其他时间每5分钟增加1人 出去1个人 14~18点,相当于每分钟减少0.8人
# 18点-20点每分钟增加20人 出去1个人 相当于18~20点,每分钟增加19人
times = [
[8 * 60, 10 * 60, 2],
[10 * 60, 12 * 60, -0.8],
[12 *60, 14 * 60, 9],
[14 * 60, 18 * 60, -0.8],
[18 * 60, 20 * 60, 19]
]
def mapFn(target):
# [核酸点id, 核酸点和张三的距离, 核酸点在张三出发时已有的人数]
id, dis, wait = target
arrived = start + dis * 10 # 每公里距离花费时间10分钟,费用是10元
if arrived < 8*60: # 8点之前到
arrived = 8*60 # 到达时间就是8点,排在初始人数后面。
return [id,arrived-start+wait,dis *10]
s1 = start # 算开始时间,
e1 = arrived # 到达时间。然后取交集。在加上增速。
for s2, e2, changePerMin in times:
t = intersection(s1, e1, s2, e2)
# 存在交叉的区间。
if t > 0: # 重叠了多少区间,这个区间内按照比例增加。
wait += t * changePerMin
wait = max(0, wait) # 要注意,因为存在的人数减少的情况,所以要跟0取max
return [id, arrived-start+int(wait), dis*10]
ans = list(filter(lambda x: start+x[1]<=except_end, map(mapFn, targets))) # 非常棒啊。
ans.sort(key=lambda x:(x[1], x[2], x[0])) # 不用判断ans>0?
print(len(ans))
for a in ans:
print(" ".join(list(map(str, a))))
result()
参考链接:
1、知乎——python之map()函数
2、知乎——python之filter()函数
3、labuladong算法学习总结