解法一:队列+模拟
用N个队列模拟银行窗口的队列,每次找出排在第一位且完成时间最早、窗口编号最小的顾客办理业务,并更然后加入一位未进入队列的顾客,更新队首顾客的完成时间。
需要注意的一个坑:如果一个顾客开始办理业务的时间早于17:00,完成时间晚于17:00,那么银行也需要为他办理业务。
import java.io.*;import java.util.*;public class Main {public static void main(String[] args) throws IOException {StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));in.nextToken();int N = (int) in.nval;in.nextToken();int M = (int) in.nval;in.nextToken();int K = (int) in.nval;in.nextToken();int Q = (int) in.nval;Customer[] customers = new Customer[K];for (int i = 0; i < K; ++i) {in.nextToken();customers[i] = new Customer((int) in.nval);}List<Queue<Customer>> windows = new ArrayList<>();for (int i = 0; i < N; ++i) {windows.add(new LinkedList<>());}int toAdd;for (toAdd = 0; (toAdd < K) && (toAdd < N * M); ++toAdd) {windows.get(toAdd % N).offer(customers[toAdd]);}int todo = 0;while (todo < K) {int min = 0x3f3f3f3f;Customer next = null;int windowID = -1;for (int i = 0; i < windows.size(); ++i) {Customer customer = windows.get(i).peek();if (customer == null) {continue;}// 完成时间最短, 窗口编号小的优先if ((customer.time - customer.cost < 540) && (customer.time < min)) {min = customer.time;next = customer;windowID = i;}}// 没有需要服务的客户if (next == null) {break;}// 更新自己和队列中下一个人的状态next.isFinish = true;Queue<Customer> queue = windows.get(windowID);queue.poll();if (toAdd < K) {queue.offer(customers[toAdd++]);}if (!queue.isEmpty()) {queue.peek().time += next.time;}++todo;}for (int i = 0; i < Q; ++i) {in.nextToken();int index = (int) in.nval - 1;out.println(customers[index]);}out.flush();}}class Customer {// 处理时间int cost;// 完成时间int time;// 是否能被银行处理boolean isFinish;public Customer(int cost) {this.cost = cost;time = cost;isFinish = false;}@Overridepublic String toString() {if (isFinish) {int minute = (time + 480) / 60;int second = time % 60;return String.format("%02d:%02d", minute, second);}return "Sorry";}}
