pat——1017. Queueing at Bank (java中Map用法)

时间:2023-01-31 04:07:52

由PAT1017例题展开:

Suppose a bank has K windows open for service. There is a yellow line in front of the windows which devides the waiting area into two parts. All the customers have to wait in line behind the yellow line, until it is his/her turn to be served and there is a window available. It is assumed that no window can be occupied by a single customer for more than 1 hour.

Now given the arriving time T and the processing time P of each customer, you are supposed to tell the average waiting time of all the customers.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 numbers: N (<=10000) - the total number of customers, and K (<=100) - the number of windows. Then N lines follow, each contains 2 times: HH:MM:SS - the arriving time, and P - the processing time in minutes of a customer. Here HH is in the range [00, 23], MM and SS are both in [00, 59]. It is assumed that no two customers arrives at the same time.

Notice that the bank opens from 08:00 to 17:00. Anyone arrives early will have to wait in line till 08:00, and anyone comes too late (at or after 17:00:01) will not be served nor counted into the average.

Output Specification:

For each test case, print in one line the average waiting time of all the customers, in minutes and accurate up to 1 decimal place.

Sample Input:

7 3
07:55:00 16
17:00:01 2
07:59:59 15
08:01:00 60
08:00:00 30
08:00:02 2
08:03:00 10

Sample Output:

8.2

本题目的基本思路:首先对每一个客户的进入银行时间进行排序(并且每个人进入银行的时间是独一无二的),每个用户包括两个时间(startTime ,processTime)

其次,每个客户都是选择最先有空余时间的窗口进行,需要计算好每一个客户完成工作的时候该窗口的时间。

如果客户到达的时候没有空余窗口,则需要结合第二步,计算该客户需要等待的最短时间。

 package com.hone.advanced;
import java.util.Map;
import java.util.Scanner;
import java.util.Stack;
import java.util.TreeMap; /**
* source:https://www.patest.cn/contests/pat-a-practise/1017
* @author Xia
* 将时间全部处理成小数
*/
public class Adavanced1017QueueingatBank {
private static final int start = 8*60*60;
private static final int end = 15*60*60; public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
int waitTime = 0; //用于保存每一个人的到达时间和办理业务需要的时间
//利用TreeMap 保证进入的时间独一无二,并且按照key排序
Map<Integer, Integer> personMap = new TreeMap<Integer, Integer>(); int[] windows = new int[k]; int arr_time = 0;
int proc_time = 0;
for (int i = 0; i < n; i++) {
arr_time = getTime(in.next());
proc_time = in.nextInt()*60;
if (arr_time < end)
personMap.put(arr_time, proc_time);
} //为每个窗口设定开始的时间
for (int i = 0; i < k; i++) {
windows[i] = start;
}
for (int key : personMap.keySet()) {
waitTime += wait(key, personMap.get(key), windows, k);
}
System.out.printf("%.1f", waitTime / 60.0 / personMap.size());
} //计算一个人等待所需要花费的时间
private static int wait(int start, int process, int[] windows, int k) {
int time = 0;
int min = Integer.MAX_VALUE;
int min_i = 0;
for (int i = 0; i < k; i++) {
//如果客户来得时候刚有有空缺窗口,则直接开始在该窗口办理业务,等待时间为零
if (start > windows[i] ) {
windows[i] = start+process;
return 0;
}else {
//如果来得时候没有空缺窗口,比较哪个窗口时间最短,
if (windows[i] < min) {
min = windows[i];
min_i = i;
}
}
}
//计算等待最短等待窗口所需要的时间
time = windows[min_i]-start;
windows[min_i] = windows[min_i] + process;
return time;
} //处理所有人的时间(全部转化成秒)
private static int getTime(String stime) {
String[] time = stime.split(":");
return Integer.parseInt(time[0])*60*60+Integer.valueOf(time[1]).intValue()*60
+Integer.valueOf(time[2]).intValue();
}
}

可以注意到代码中利用的treeMap.

下面来总结一下Map的用法:

来看一下官方API中的定义:Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值。从概念上而言,您可以将 List 看作是只具有数值键的 Map。

对于map接口本身:

一般继承map都接都建议重写下面两种方法:

equals(Object o) 比较指定对象与此 Map 的等价性
hashCode() 返回此 Map 的哈希码

1:Map的构建

主要定义了插入和删除的一些方法:

clear() 从 Map 中删除所有映射
remove(Object key) 从 Map 中删除键和关联的值
put(Object key, Object value) 将指定值与指定键相关联
putAll(Map t) 将指定 Map 中的所有映射复制到此 map

2:查看Map

entrySet() 返回 Map 中所包含映射的 Set 视图。Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() 和 getValue() 方法(还有一个 setValue() 方法)访问后者的键元素和值元素
keySet() 返回 Map 中所包含键的 Set 视图。删除 Set 中的元素还将删除 Map 中相应的映射(键和值)
values() 返回 map 中所包含值的 Collection 视图。删除 Collection 中的元素还将删除 Map 中相应的映射(键和值)

如果要进行迭代,则必须获得一个要进行迭代,您必须获得一个 Iterator 对象,或者使用foreach遍历。

  • 所有键值对 — 参见 entrySet()           (返回set集合)
  • 所有键 — 参见 keySet()                          (返回set集合)
  • 有值 — 参见 values()                              (返回 Collection 对象)

遍历Map

 package com.hone.test;

 import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry; /**
* map的测试
* @author Xia
* 测试:姓名:年龄
*/
public class MapTest {
public static void main(String[] args) {
HashMap<String, Integer> person = new HashMap<>();
person.put("xiaoming", 12);
person.put("xiaolan", 18);
person.put("zhangsan", 30);
//获得所有的键
Iterator keys = person.keySet().iterator();
while (keys.hasNext()) {
String personName = (String) keys.next();
System.out.println("姓名:"+personName);
} //遍历所有的值
Iterator values = person.values().iterator();
while (values.hasNext()) {
int personaAge = (int) values.next();
System.out.println("年龄:"+personaAge);
} //遍历键值对
Iterator keyAndValues = person.entrySet().iterator();
while (keyAndValues.hasNext()) {
Map.Entry<String, Integer> entry = (Entry<String, Integer>) keyAndValues.next();
String name = entry.getKey();
int age = entry.getValue();
System.out.println("name:"+name+"\t age:"+age);
}
} }

3:访问元素

Map 通常适合按键(而非按值)进行访问。

get(Object key) 返回与指定键关联的值
containsKey(Object key) 如果 Map 包含指定键的映射,则返回 true
containsValue(Object value) 如果此 Map 将一个或多个键映射到指定值,则返回 true
isEmpty() 如果 Map 不包含键-值映射,则返回 true
size() 返回 Map 中的键-值映射的数目

java中自带有多种Map类

主要常用的有:HashMapTreeMapHashtableSortedMap

而最常见的为HashMap,TreeMap

我们来看一下官方对于hash 的介绍:

哈希映射结构由一个存储元素的内部数组组成。由于内部采用数组存储,因此必然存在一个用于确定任意键访问数组的索引机制。实际上,该机制需要提供一个小于数组大小的整数

索引值。该机制称作哈希函数。在 Java 基于哈希的 Map 中,哈希函数将对象转换为一个适合内部数组的整数。

pat——1017. Queueing at Bank  (java中Map用法)

该图介绍了哈希映射的基本原理,但我们还没有对其进行详细介绍。我们的哈希函数将任意对象映射到一个数组位置,但如果两个不同的键映射到相同的位置,情况将会如何? 这是一种必然发生的情况。在哈希映射的术语中,这称作冲突。Map 处理这些冲突的方法是在索引位置处插入一个链接列表,并简单地将元素添加到此链接列表。