【华为OD-B卷-打印文件 100分(python、java、c++、js、c)】
题目
有5台打印机打印文件,每台打印机有自己的待打印队列。
因为打印的文件内容有轻重缓急之分,所以队列中的文件有1~10不同的代先级,其中数字越大优先级越高。
打印机会从自己的待打印队列中选择优先级最高的文件来打印。
如果存在两个优先级一样的文件,则选择最早进入队列的那个文件。
现在请你来模拟这5台打印机的打印过程。
输入描述
- 每个输入包含1个测试用例,
每个测试用例第一行给出发生事件的数量N(0 < N < 1000)。
接下来有 N 行,分别表示发生的事件。共有如下两种事件:
"IN P NUM",表示有一个拥有优先级 NUM 的文件放到了打印机 P 的待打印队列中。(0< P <= 5, 0 < NUM <= 10); "OUT P",表示打印机 P 进行了一次文件打印,同时该文件从待打印队列中取出。(0 < P <= 5)
输出描述
- 对于每个测试用例,每次"OUT P"事件,请在一行中输出文件的编号。 如果此时没有文件可以打印,请输出"NULL"。 文件的编号定义为"IN P NUM"事件发生第 x 次,此处待打印文件的编号为x。编号从1开始
用例
用例一:
输入:
7
IN 1 1
IN 1 2
IN 1 3
IN 2 1
OUT 1
OUT 2
OUT 2
输出:
3
4
NULL
用例二:
输入:
5
IN 1 1
IN 1 3
IN 1 1
IN 1 3
OUT 1
输出:
2
python解法
- 解题思路:
-
解题思路
题目回顾
有 5 台打印机,每台有独立的待打印队列;
每个队列中的文件具有:
优先级(1~10),越大越优先;
先进先出(同优先级按加入顺序);
两种事件类型:
"IN P NUM":编号为 x 的文件以优先级 NUM 加入打印机 P 的队列;
"OUT P":打印机 P 打印优先级最高、加入最早的文件;
每次 "OUT" 输出打印的文件编号,如果为空输出 "NULL"。
✅ 实现思路
使用 defaultdict(deque) 为每个打印机维护一个队列(打印任务池);
每次 "IN P NUM" 事件,将文件加入打印机 P 的队列;
记录:优先级、加入顺序、编号(即事件序号);
每次 "OUT P":
遍历队列中所有任务,按 优先级降序、时间升序 排序;
取出第一个任务(最高优先级 + 最早加入),输出其编号;
将该任务从队列中删除;
维护一个全局编号 idx,自增标记文件编号。
- 使用到的算法
defaultdict(deque) 按打印机编号分类管理队列任务
自定义排序(lambda) 按优先级(降序)和顺序(升序)选任务
队列(FIFO) 保证同优先级时,最早加入任务优先出队
python
from collections import defaultdict, deque
def get_result(tasks):
mp = defaultdict(deque) # 打印机编号 -> 任务队列(deque)
idx = 1 # 文件编号,从1开始
for i, t in enumerate(tasks): # 遍历每个事件
if t[0] == 'IN':
# IN P NUM:t[1]是打印机编号,t[2]是优先级
# 添加任务 (优先级,加入时间,用于排序),i是当前事件序号,idx是文件编号
mp[t[1]].append((int(t[2]), i, idx))
idx += 1 # 文件编号递增
else: # OUT P:打印机 P 执行一次打印任务
lst = list(mp[t[1]]) # 获取打印机 t[1] 的任务列表
if not lst:
print('NULL') # 无任务可打印
continue
# 排序规则:优先级降序,加入时间升序
lst.sort(key=lambda x: (-x[0], x[1])) # x = (优先级, 时间, 编号)
top = lst[0] # 取排序后第一个为要打印的文件
mp[t[1]].remove(top) # 从打印机队列中删除它
print(top[2]) # 输出文件编号
java解法
- 解题思路
-
解题思路
题目回顾
有 5台打印机(编号 1~5),每台有独立的待打印队列;
每个文件有一个优先级(1~10,越大优先级越高);
每台打印机执行 "OUT" 操作时:
打印优先级最高的文件;
如果优先级相同,则选择最早加入的那个;
文件编号按 "IN" 事件顺序递增,从 1 开始;
输出每次 "OUT" 操作的文件编号,如果队列为空,输出 "NULL"。
✅ 解法设计
使用 Map<String, List<int[]>> 来存储每台打印机的待打印队列;
key 是打印机编号(字符串);
value 是当前打印机上的文件队列,每个文件用 int[]{优先级, 时间戳, 编号} 表示;
"IN P NUM" 操作:加入到指定打印机的队列;
"OUT P" 操作:
遍历打印机 P 的任务队列;
使用 Collections.min() + 自定义比较器,选出优先级高、加入早的文件;
打印编号并从队列中移除;
如果该打印机没有文件,输出 "NULL"。
🧮 2. 使用到的算法与数据结构
Map<String, List<int[]>> 存储每台打印机的任务队列
Collections.min() + Lambda 找出当前打印机队列中应打印的文件
自定义排序 比较优先级(降序)、时间(升序)
ArrayList 动态维护队列,支持随机访问和删除
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = Integer.parseInt(sc.nextLine()); // 读取事件总数 N
List<String[]> ls = new ArrayList<>();
for (int i = 0; i < n; i++) {
// 每行事件分割成数组 ["IN", "1", "5"] 或 ["OUT", "3"]
ls.add(sc.nextLine().split(" "));
}
run(ls); // 执行模拟操作
}
public static void run(List<String[]> ls) {
// mp:每台打印机编号 -> 对应任务队列(List<int[]>)
Map<String, List<int[]>> mp = new HashMap<>();
int idx = 1; // 文件编号从1开始,每次IN操作后递增
for (int i = 0; i < ls.size(); i++) {
String[] t = ls.get(i); // 当前事件数组 t,如 ["IN", "1", "5"]
if (t[0].equals("IN")) {
// 获取打印机编号 t[1],优先级 t[2]
mp.putIfAbsent(t[1], new ArrayList<>()); // 若不存在则新建队列
// 添加任务到打印机队列:{优先级,事件顺序号,用于时间排序,编号}
mp.get(t[1]).add(new int[]{Integer.parseInt(t[2]), i, idx++});
} else {
// "OUT" 操作:判断打印机是否有任务
if (!mp.containsKey(t[1]) || mp.get(t[1]).isEmpty()) {
System.out.println("NULL"); // 无任务可打印
} else {
List<int[]> lst = mp.get(t[1]); // 获取打印机任务列表
// 自定义排序:优先级降序,时间戳升序
int[] top = Collections.min(lst, (a, b) -> {
if (a[0] != b[0]) return b[0] - a[0]; // 优先级高的排前面
return a[1] - b[1]; // 时间早的排前面
});
lst.remove(top); // 从任务队列中移除被打印的文件
System.out.println(top[2]); // 输出文件编号
}
}
}
}
}
C++解法
- 解题思路
c++
更新中
C解法
解题思路
c
更新中
JS解法
解题思路
javascript
更新中
注意:
如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏