这个题满满的都是套路。其实根本不难,就是一个双向队列的问题。如果你只看了紫书的话,那么你完蛋了,因为这个紫书数条件给的不够。你需要去看原题,并且要把它完整地翻译过来。
坑
-
这个题是有多个输入的,这个一般中文翻译都没有,需要去看原题。
-
时间片用完之后,如果正在执行语句,那么这个语句将继续执行下去,哪怕最后时间为负数。并不是说时间一到就不执行了。
-
输入的时候首先要告诉你有几个输入,随后空一行。然后开始正式的一个输入块;输入块完成后,再空一行开始另一个输入块,循环往复。
-
输出时每个输入块对应一个输出块,然后空一行再开始另一个输出块。最后一个输出块不用空最后一行。
思路
按照操作系统的做法:设计一个就绪队列,一个阻塞队列还有一个运行队列。在使用Java的双端队列API,整个题就非常的简单了。
package com.ahyer;
import java.util.*;
public class Main {
static List<Program> list = new ArrayList<>();
static Deque<Program> runState = new LinkedList<>();
static Deque<Program> prepareState = new LinkedList<>();
static Deque<Program> blockState = new LinkedList<>();
static Map<String, String> map = new HashMap<>();
static boolean block = false;
static class Program {
Deque<Statement> deque = new ArrayDeque<>();
int programID;
}
static class Statement {
String statement;
int remain;
int id;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.nextLine();
int per = Integer.parseInt(s);
while (per-- != 0) {
list.clear();
blockState.clear();
runState.clear();
prepareState.clear();
map.clear();
scanner.nextLine();
String s1 = scanner.nextLine();
String[] s2 = s1.split(" ");
int program = Integer.parseInt(s2[0]);
int t1 = Integer.parseInt(s2[1]);
int t2 = Integer.parseInt(s2[2]);
int t3 = Integer.parseInt(s2[3]);
int t4 = Integer.parseInt(s2[4]);
int t5 = Integer.parseInt(s2[5]);
int Q = Integer.parseInt(s2[6]);
for (int i = 0; i < program; i++) {
list.add(new Program());
}
int programeNums = 0;
while (programeNums != program) {
String s3 = scanner.nextLine();
if (s3.equals("")) break;
Statement statement = new Statement();
list.get(programeNums).deque.addLast(statement);
list.get(programeNums).programID = programeNums + 1;
statement.statement = s3;
if (s3.contains("=")) {
statement.id = 1;
statement.remain = t1;
} else if (s3.contains("print")) {
statement.id = 2;
statement.remain = t2;
} else if (s3.equals("lock")) {
statement.remain = t3;
statement.id = 3;
} else if (s3.equals("unlock")) {
statement.remain = t4;
statement.id = 4;
} else {
statement.remain = t5;
statement.id = 5;
prepareState.addLast(list.get(programeNums++));
}
}
//输入完成了
while (!prepareState.isEmpty() || !blockState.isEmpty() || !runState.isEmpty()) {
if (!prepareState.isEmpty()) {
runState.addFirst(prepareState.removeFirst());
}
Program runProgram = runState.getFirst();
int time = Q;
while (time > 0) {
int remain = runProgram.deque.getFirst().remain;
if (solve(runProgram)) {
break;
}
time -= remain;
}
if (!runState.isEmpty()) {
prepareState.addLast(runState.removeFirst());
}
}
if (per != 0) {
System.out.println();
}
}
}
private static boolean solve(Program runProgram) {
String statement = runProgram.deque.getFirst().statement;
String[] split = null;
//程序代码序列
if (runProgram.deque.getFirst().id == 3 && block) {
blockState.addLast(runState.removeFirst());
return true;
}
switch (runProgram.deque.removeFirst().id) {
case 1:
split = statement.split(" ");
map.put(split[0], split[2]);
break;
case 2:
split = statement.split(" ");
if (map.get(split[1]) == null) {
map.put(split[1], "0");
}
System.out.println(runProgram.programID + ": " + map.get(split[1]));
break;
case 3:
block = true;
break;
case 4:
block = false;
if (!blockState.isEmpty()) {
prepareState.addFirst(blockState.removeFirst());
}
break;
case 5:
//本程序结束了
runState.removeFirst();
return true;
default:
break;
}
return false;
}
}
这个双端队列的API。最好分开写,因为如果单独写的话,如果这个队列只有一个元素,那么你连着写remove()掉再addLast()那就相当于没有变。上面这个代码不存在这种问题,因为操作多个队列。