一部电梯在 1 楼到 F 楼之间上下运行,一次最多载 K 人。 有 n 位乘客,按输入顺序编号 1 到 n。 第 i 位乘客在第 t_i 分钟来到 a_i 楼,要去 b_i 楼。 电梯的方向是"上""下""停"之一。 第 0 分钟时电梯空着停在 1 楼,方向为"停"。 当前时刻为第 T 分钟、电梯在 f 楼时,依次执行以下五步。 第 1 步:第 T 分钟到来的乘客排到自己楼层队伍的末尾。 同一时刻到来的乘客按编号顺序排队。 第 2 步:电梯里要去 f 楼的乘客全部下电梯,他们的到达时刻是 T。 第 3 步:决定方向。"上方有事"是指以下至少有一人:电梯里要去 f 楼以上的乘客、在 f 楼以上楼层等待的乘客、在 f 楼等待且要往上的乘客。"下方有事"同样看下方。 - 方向为"上"且上方有事就保持"上"。 上方无事时,若下方有事改为"下",否则改为"停"。 - 方向为"下"时同理:下方有事就保持,否则若上方有事改为"上",否则改为"停"。 - 方向为"停"时,看当前等待的乘客中编号最小的乘客 P。 P 在别的楼层就朝 P 所在楼层的方向,P 在 f 楼就朝 P 要去的方向。 没有人等待就保持"停"。 是编号最小的乘客,而不是最近的乘客。 第 4 步:方向不是"停"时,f 楼队伍中要往这个方向去的乘客按排队顺序上电梯。 电梯里已有 K 人就不能再上。 没能上的乘客和要往另一个方向去的乘客保持排队顺序继续等待。 第 5 步:方向为"上"就上一层,为"下"就下一层,时刻变为 T + 1。 方向为"停"就留在该楼层,直接跳到下一位乘客到来的时刻。 所有乘客都到达后结束。 第一行给出 F、K、n,接下来 n 行给出 t_i、a_i、b_i,用一个空格隔开。 按编号顺序每行输出一位乘客的到达时刻。
输入
2 ≤ F ≤ 30,1 ≤ K ≤ 10,1 ≤ n ≤ 500,0 ≤ t_i ≤ 1,000,000,1 ≤ a_i, b_i ≤ F,a_i ≠ b_i(均为整数)。 t_i 随编号增大而不减少。
输出
n 行,每位乘客的到达时刻
样例 1 · stdin
6 2 5
0 1 4
0 3 1
1 2 5
2 5 3
2 6 5
stdout
3
10
4
8
6
main.py
错误列表00F8 ↓ · ⇧F8 ↑
输入(stdin)
运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。
$ 就绪
请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。
其他语言怎么写?查看各语言题解 · 8 种语言题解
这是把规则一步一步照搬成代码的模拟题。 每层一个等待队列(列表的列表),再加一个乘客列表,每分钟依次执行五步。 无事可做时还一分钟一分钟地数,会空转一百万分钟,所以方向为"停"时直接跳到下一位乘客到来的时刻。 从电梯乘客列表中去掉下电梯的人,各语言写法不同:Python 用列表推导式生成新列表,JS、TS 用 filter,Java 用 Iterator.remove()(在 for-each 里调用 list.remove 通常会抛 ConcurrentModificationException),C# 用 RemoveAll(p => …)(在 foreach 里删除会抛 InvalidOperationException),C 把留下的人挤到数组前面再减少个数,C++20 有 std::erase_if,Craykon 用留下的人建新列表。 从队伍里去掉上电梯的人时,同样保持其余人的顺序建一个新队伍。 六个陷阱:① 不看方向就让所有人上,会把要去反方向的乘客也带走。 ② 先上后下,会在满员时就让人上,明明这一层会空出位置却上不去。 ③ 停着时去找最近的乘客是错的,应该去找编号最小的乘客。 ④ 一直走到最端的楼层才掉头(SCAN)是错的,本题没有更多事要做就当场掉头(LOOK)。 ⑤ 用 <= K 比较座位数会多上一个人。 ⑥ 停着时 P 在别的楼层,却朝 P 的目的地出发,就不会去接 P。
Pythonmain.py · 59 行
import sysdef main(): data = sys.stdin.read().split() floors, cap, n = int(data[0]), int(data[1]), int(data[2]) t = [int(data[3 + 3 * i]) for i in range(n)] a = [int(data[4 + 3 * i]) for i in range(n)] b = [int(data[5 + 3 * i]) for i in range(n)] waiting = [[] for _ in range(floors + 1)] # 층마다 기다리는 사람 번호(온 차례) inside = [] # 타고 있는 사람 번호 arrive = [0] * n now, floor, direction = 0, 1, 0 # 방향: 1 위, -1 아래, 0 멈춤 nxt = done = 0 while done < n: # 1) 이 시각에 온 사람이 줄을 선다 while nxt < n and t[nxt] == now: waiting[a[nxt]].append(nxt) nxt += 1 # 2) 내릴 사람이 내린다 for p in [p for p in inside if b[p] == floor]: arrive[p] = now done += 1 inside = [p for p in inside if b[p] != floor] # 3) 방향을 정한다 up = any(b[p] > floor for p in inside) or any(waiting[g] for g in range(floor + 1, floors + 1)) \ or any(b[p] > floor for p in waiting[floor]) down = any(b[p] < floor for p in inside) or any(waiting[g] for g in range(1, floor)) \ or any(b[p] < floor for p in waiting[floor]) if direction == 1 and not up: direction = -1 if down else 0 elif direction == -1 and not down: direction = 1 if up else 0 elif direction == 0: first = min((p for g in range(1, floors + 1) for p in waiting[g]), default=None) if first is not None: target = a[first] if a[first] != floor else b[first] direction = 1 if target > floor else -1 # 4) 같은 방향으로 갈 사람이 온 차례대로, 자리가 있는 만큼 탄다 if direction != 0: stay = [] for p in waiting[floor]: if (b[p] - floor) * direction > 0 and len(inside) < cap: inside.append(p) else: stay.append(p) waiting[floor] = stay if done == n: break # 5) 한 층 옮긴다. 할 일이 없으면 다음 사람이 올 때까지 건너뛴다 if direction == 0: now = t[nxt] else: floor += direction now += 1 print("\n".join(map(str, arrive)))main()
JavaScriptmain.js · 55 行
const d = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [floors, cap, n] = d;const t = [], a = [], b = [];for (let i = 0; i < n; i++) { t.push(d[3 + 3 * i]); a.push(d[4 + 3 * i]); b.push(d[5 + 3 * i]);}let waiting = Array.from({ length: floors + 1 }, () => []); // 층마다 기다리는 사람 번호(온 차례)let inside = []; // 타고 있는 사람 번호const arrive = new Array(n).fill(0);let now = 0, floor = 1, dir = 0; // 방향: 1 위, -1 아래, 0 멈춤let next = 0, done = 0;while (done < n) { // 1) 이 시각에 온 사람이 줄을 선다 while (next < n && t[next] === now) waiting[a[next]].push(next++); // 2) 내릴 사람이 내린다 for (const p of inside) if (b[p] === floor) { arrive[p] = now; done++; } inside = inside.filter((p) => b[p] !== floor); // 3) 방향을 정한다 let up = inside.some((p) => b[p] > floor) || waiting[floor].some((p) => b[p] > floor); let down = inside.some((p) => b[p] < floor) || waiting[floor].some((p) => b[p] < floor); for (let g = 1; g <= floors; g++) { if (waiting[g].length === 0) continue; if (g > floor) up = true; if (g < floor) down = true; } if (dir === 1 && !up) dir = down ? -1 : 0; else if (dir === -1 && !down) dir = up ? 1 : 0; else if (dir === 0) { let first = -1; // 기다리는 사람 가운데 가장 먼저 온 사람 for (let g = 1; g <= floors; g++) if (waiting[g].length > 0 && (first < 0 || waiting[g][0] < first)) first = waiting[g][0]; if (first >= 0) { const target = a[first] !== floor ? a[first] : b[first]; dir = target > floor ? 1 : -1; } } // 4) 같은 방향으로 갈 사람이 온 차례대로, 자리가 있는 만큼 탄다 if (dir !== 0) { const stay = []; for (const p of waiting[floor]) { if ((b[p] - floor) * dir > 0 && inside.length < cap) inside.push(p); else stay.push(p); } waiting[floor] = stay; } if (done === n) break; // 5) 한 층 옮긴다. 할 일이 없으면 다음 사람이 올 때까지 건너뛴다 if (dir === 0) now = t[next]; else { floor += dir; now++; }}console.log(arrive.join("\n"));
TypeScriptmain.ts · 55 行
const d: number[] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [floors, cap, n] = d;const t: number[] = [], a: number[] = [], b: number[] = [];for (let i = 0; i < n; i++) { t.push(d[3 + 3 * i]); a.push(d[4 + 3 * i]); b.push(d[5 + 3 * i]);}let waiting: number[][] = Array.from({ length: floors + 1 }, () => []); // 층마다 기다리는 사람 번호(온 차례)let inside: number[] = []; // 타고 있는 사람 번호const arrive: number[] = new Array(n).fill(0);let now = 0, floor = 1, dir = 0; // 방향: 1 위, -1 아래, 0 멈춤let next = 0, done = 0;while (done < n) { // 1) 이 시각에 온 사람이 줄을 선다 while (next < n && t[next] === now) waiting[a[next]].push(next++); // 2) 내릴 사람이 내린다 for (const p of inside) if (b[p] === floor) { arrive[p] = now; done++; } inside = inside.filter((p) => b[p] !== floor); // 3) 방향을 정한다 let up = inside.some((p) => b[p] > floor) || waiting[floor].some((p) => b[p] > floor); let down = inside.some((p) => b[p] < floor) || waiting[floor].some((p) => b[p] < floor); for (let g = 1; g <= floors; g++) { if (waiting[g].length === 0) continue; if (g > floor) up = true; if (g < floor) down = true; } if (dir === 1 && !up) dir = down ? -1 : 0; else if (dir === -1 && !down) dir = up ? 1 : 0; else if (dir === 0) { let first = -1; // 기다리는 사람 가운데 가장 먼저 온 사람 for (let g = 1; g <= floors; g++) if (waiting[g].length > 0 && (first < 0 || waiting[g][0] < first)) first = waiting[g][0]; if (first >= 0) { const target = a[first] !== floor ? a[first] : b[first]; dir = target > floor ? 1 : -1; } } // 4) 같은 방향으로 갈 사람이 온 차례대로, 자리가 있는 만큼 탄다 if (dir !== 0) { const stay: number[] = []; for (const p of waiting[floor]) { if ((b[p] - floor) * dir > 0 && inside.length < cap) inside.push(p); else stay.push(p); } waiting[floor] = stay; } if (done === n) break; // 5) 한 층 옮긴다. 할 일이 없으면 다음 사람이 올 때까지 건너뛴다 if (dir === 0) now = t[next]; else { floor += dir; now++; }}console.log(arrive.join("\n"));
JavaMain.java · 83 行
import java.io.*;import java.util.*;public class Main { public static void main(String[] args) throws IOException { StreamTokenizer in = new StreamTokenizer(new BufferedInputStream(System.in)); in.nextToken(); int floors = (int) in.nval; in.nextToken(); int cap = (int) in.nval; in.nextToken(); int n = (int) in.nval; int[] t = new int[n], a = new int[n], b = new int[n]; for (int i = 0; i < n; i++) { in.nextToken(); t[i] = (int) in.nval; in.nextToken(); a[i] = (int) in.nval; in.nextToken(); b[i] = (int) in.nval; } List<List<Integer>> waiting = new ArrayList<>(); // 층마다 기다리는 사람 번호(온 차례) for (int g = 0; g <= floors; g++) waiting.add(new ArrayList<>()); List<Integer> inside = new ArrayList<>(); int[] arrive = new int[n]; int now = 0, floor = 1, dir = 0; // 방향: 1 위, -1 아래, 0 멈춤 int next = 0, done = 0; while (done < n) { // 1) 이 시각에 온 사람이 줄을 선다 while (next < n && t[next] == now) waiting.get(a[next]).add(next++); // 2) 내릴 사람이 내린다 for (Iterator<Integer> it = inside.iterator(); it.hasNext(); ) { int p = it.next(); if (b[p] == floor) { arrive[p] = now; done++; it.remove(); } } // 3) 방향을 정한다 boolean up = false, down = false; for (int p : inside) { if (b[p] > floor) up = true; if (b[p] < floor) down = true; } for (int p : waiting.get(floor)) { if (b[p] > floor) up = true; if (b[p] < floor) down = true; } for (int g = 1; g <= floors; g++) { if (waiting.get(g).isEmpty()) continue; if (g > floor) up = true; if (g < floor) down = true; } if (dir == 1 && !up) dir = down ? -1 : 0; else if (dir == -1 && !down) dir = up ? 1 : 0; else if (dir == 0) { int first = -1; for (int g = 1; g <= floors; g++) { List<Integer> w = waiting.get(g); if (!w.isEmpty() && (first < 0 || w.get(0) < first)) first = w.get(0); } if (first >= 0) { int target = a[first] != floor ? a[first] : b[first]; dir = target > floor ? 1 : -1; } } // 4) 같은 방향으로 갈 사람이 온 차례대로, 자리가 있는 만큼 탄다 if (dir != 0) { List<Integer> stay = new ArrayList<>(); for (int p : waiting.get(floor)) { if ((b[p] - floor) * dir > 0 && inside.size() < cap) inside.add(p); else stay.add(p); } waiting.set(floor, stay); } if (done == n) break; // 5) 한 층 옮긴다. 할 일이 없으면 다음 사람이 올 때까지 건너뛴다 if (dir == 0) now = t[next]; else { floor += dir; now++; } } StringBuilder sb = new StringBuilder(); for (int x : arrive) sb.append(x).append('\n'); System.out.print(sb); }}
C#Main.cs · 75 行
using System;using System.Collections.Generic;using System.Text;class Program{ static void Main() { var d = Array.ConvertAll(Console.In.ReadToEnd().Split((char[])null, StringSplitOptions.RemoveEmptyEntries), int.Parse); int floors = d[0], cap = d[1], n = d[2]; int[] t = new int[n], a = new int[n], b = new int[n]; for (int i = 0; i < n; i++) { t[i] = d[3 + 3 * i]; a[i] = d[4 + 3 * i]; b[i] = d[5 + 3 * i]; } var waiting = new List<int>[floors + 1]; // 층마다 기다리는 사람 번호(온 차례) for (int g = 0; g <= floors; g++) waiting[g] = new List<int>(); var inside = new List<int>(); var arrive = new int[n]; int now = 0, floor = 1, dir = 0; // 방향: 1 위, -1 아래, 0 멈춤 int next = 0, done = 0; while (done < n) { // 1) 이 시각에 온 사람이 줄을 선다 while (next < n && t[next] == now) { waiting[a[next]].Add(next); next++; } // 2) 내릴 사람이 내린다 foreach (int p in inside) if (b[p] == floor) { arrive[p] = now; done++; } inside.RemoveAll(p => b[p] == floor); // 3) 방향을 정한다 bool up = false, down = false; foreach (int p in inside) { if (b[p] > floor) up = true; if (b[p] < floor) down = true; } foreach (int p in waiting[floor]) { if (b[p] > floor) up = true; if (b[p] < floor) down = true; } for (int g = 1; g <= floors; g++) { if (waiting[g].Count == 0) continue; if (g > floor) up = true; if (g < floor) down = true; } if (dir == 1 && !up) dir = down ? -1 : 0; else if (dir == -1 && !down) dir = up ? 1 : 0; else if (dir == 0) { int first = -1; for (int g = 1; g <= floors; g++) if (waiting[g].Count > 0 && (first < 0 || waiting[g][0] < first)) first = waiting[g][0]; if (first >= 0) { int target = a[first] != floor ? a[first] : b[first]; dir = target > floor ? 1 : -1; } } // 4) 같은 방향으로 갈 사람이 온 차례대로, 자리가 있는 만큼 탄다 if (dir != 0) { var stay = new List<int>(); foreach (int p in waiting[floor]) { if ((b[p] - floor) * dir > 0 && inside.Count < cap) inside.Add(p); else stay.Add(p); } waiting[floor] = stay; } if (done == n) break; // 5) 한 층 옮긴다. 할 일이 없으면 다음 사람이 올 때까지 건너뛴다 if (dir == 0) now = t[next]; else { floor += dir; now++; } } var sb = new StringBuilder(); foreach (int x in arrive) sb.Append(x).Append('\n'); Console.Write(sb); }}
C++main.cpp · 59 行
#include <algorithm>#include <iostream>#include <vector>int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int floors, cap, n; std::cin >> floors >> cap >> n; std::vector<int> t(n), a(n), b(n), arrive(n); for (int i = 0; i < n; i++) std::cin >> t[i] >> a[i] >> b[i]; std::vector<std::vector<int>> waiting(floors + 1); // 층마다 기다리는 사람 번호(온 차례) std::vector<int> inside; int now = 0, floor = 1, dir = 0; // 방향: 1 위, -1 아래, 0 멈춤 int next = 0, done = 0; while (done < n) { // 1) 이 시각에 온 사람이 줄을 선다 while (next < n && t[next] == now) waiting[a[next]].push_back(next), next++; // 2) 내릴 사람이 내린다 for (int p : inside) if (b[p] == floor) arrive[p] = now, done++; std::erase_if(inside, [&](int p) { return b[p] == floor; }); // 3) 방향을 정한다 bool up = false, down = false; for (int p : inside) up |= b[p] > floor, down |= b[p] < floor; for (int p : waiting[floor]) up |= b[p] > floor, down |= b[p] < floor; for (int g = 1; g <= floors; g++) { if (waiting[g].empty()) continue; if (g > floor) up = true; if (g < floor) down = true; } if (dir == 1 && !up) dir = down ? -1 : 0; else if (dir == -1 && !down) dir = up ? 1 : 0; else if (dir == 0) { int first = -1; for (int g = 1; g <= floors; g++) if (!waiting[g].empty() && (first < 0 || waiting[g][0] < first)) first = waiting[g][0]; if (first >= 0) { int target = a[first] != floor ? a[first] : b[first]; dir = target > floor ? 1 : -1; } } // 4) 같은 방향으로 갈 사람이 온 차례대로, 자리가 있는 만큼 탄다 if (dir != 0) { std::vector<int> stay; for (int p : waiting[floor]) { if ((b[p] - floor) * dir > 0 && (int)inside.size() < cap) inside.push_back(p); else stay.push_back(p); } waiting[floor] = stay; } if (done == n) break; // 5) 한 층 옮긴다. 할 일이 없으면 다음 사람이 올 때까지 건너뛴다 if (dir == 0) now = t[next]; else floor += dir, now++; } for (int x : arrive) std::cout << x << '\n'; return 0;}
Cmain.c · 83 行
#include <stdio.h>#define MAXN 500#define MAXF 30static int t[MAXN], a[MAXN], b[MAXN], arrive[MAXN];static int waiting[MAXF + 1][MAXN]; /* 층마다 기다리는 사람 번호(온 차례) */static int wcount[MAXF + 1];static int inside[10], icount = 0; /* 타고 있는 사람 번호 */int main(void) { int floors, cap, n; scanf("%d %d %d", &floors, &cap, &n); for (int i = 0; i < n; i++) scanf("%d %d %d", &t[i], &a[i], &b[i]); int now = 0, floor = 1, dir = 0; /* 방향: 1 위, -1 아래, 0 멈춤 */ int next = 0, done = 0; while (done < n) { /* 1) 이 시각에 온 사람이 줄을 선다 */ while (next < n && t[next] == now) { waiting[a[next]][wcount[a[next]]++] = next; next++; } /* 2) 내릴 사람이 내린다(남는 사람은 앞으로 당겨 담는다) */ int k = 0; for (int j = 0; j < icount; j++) { int p = inside[j]; if (b[p] == floor) { arrive[p] = now; done++; } else { inside[k++] = p; } } icount = k; /* 3) 방향을 정한다 */ int up = 0, down = 0; for (int j = 0; j < icount; j++) { if (b[inside[j]] > floor) up = 1; if (b[inside[j]] < floor) down = 1; } for (int j = 0; j < wcount[floor]; j++) { if (b[waiting[floor][j]] > floor) up = 1; if (b[waiting[floor][j]] < floor) down = 1; } for (int g = 1; g <= floors; g++) { if (wcount[g] == 0) continue; if (g > floor) up = 1; if (g < floor) down = 1; } if (dir == 1 && !up) dir = down ? -1 : 0; else if (dir == -1 && !down) dir = up ? 1 : 0; else if (dir == 0) { int first = -1; for (int g = 1; g <= floors; g++) if (wcount[g] > 0 && (first < 0 || waiting[g][0] < first)) first = waiting[g][0]; if (first >= 0) { int target = a[first] != floor ? a[first] : b[first]; dir = target > floor ? 1 : -1; } } /* 4) 같은 방향으로 갈 사람이 온 차례대로, 자리가 있는 만큼 탄다 */ if (dir != 0) { int *w = waiting[floor]; k = 0; for (int j = 0; j < wcount[floor]; j++) { int p = w[j]; if ((b[p] - floor) * dir > 0 && icount < cap) inside[icount++] = p; else w[k++] = p; } wcount[floor] = k; } if (done == n) break; /* 5) 한 층 옮긴다. 할 일이 없으면 다음 사람이 올 때까지 건너뛴다 */ if (dir == 0) { now = t[next]; } else { floor += dir; now++; } } for (int i = 0; i < n; i++) printf("%d\n", arrive[i]); return 0;}
Craykonmain.cray · 146 行
첫줄 = 控制台.读数字();floors = 첫줄[0];cap = 첫줄[1];n = 첫줄[2];t = [];a = [];b = [];循环 (i = 0; i < n; i++){ p = 控制台.读数字(); t.添加(p[0]); a.添加(p[1]); b.添加(p[2]);}waiting = []; // 층마다 기다리는 사람 번호(온 차례)循环 (g = 0; g <= floors; g++){ waiting.添加([]);}inside = []; // 타고 있는 사람 번호arrive = 新列表(n, 0);now = 0;floor = 1;dir = 0; // 방향: 1 위, -1 아래, 0 멈춤next = 0;done = 0;当 (done < n){ // 1) 이 시각에 온 사람이 줄을 선다 当 (next < n && t[next] == now) { waiting[a[next]].添加(next); next++; } // 2) 내릴 사람이 내린다 남은 = []; 遍历 (p 在 inside) { 如果 (b[p] == floor) { arrive[p] = now; done++; } 否则 { 남은.添加(p); } } inside = 남은; // 3) 방향을 정한다 up = 假; down = 假; 遍历 (p 在 inside) { 如果 (b[p] > floor) { up = 真; } 如果 (b[p] < floor) { down = 真; } } 遍历 (p 在 waiting[floor]) { 如果 (b[p] > floor) { up = 真; } 如果 (b[p] < floor) { down = 真; } } 循环 (g = 1; g <= floors; g++) { 如果 (waiting[g].数量 > 0 && g > floor) { up = 真; } 如果 (waiting[g].数量 > 0 && g < floor) { down = 真; } } 如果 (dir == 1 && !up) { dir = down ? -1 : 0; } 否则 如果 (dir == -1 && !down) { dir = up ? 1 : 0; } 否则 如果 (dir == 0) { first = -1; // 기다리는 사람 가운데 가장 먼저 온 사람 循环 (g = 1; g <= floors; g++) { 如果 (waiting[g].数量 > 0 && (first < 0 || waiting[g][0] < first)) { first = waiting[g][0]; } } 如果 (first >= 0) { target = a[first]; 如果 (target == floor) { target = b[first]; } dir = target > floor ? 1 : -1; } } // 4) 같은 방향으로 갈 사람이 온 차례대로, 자리가 있는 만큼 탄다 如果 (dir != 0) { stay = []; 遍历 (p 在 waiting[floor]) { 如果 ((b[p] - floor) * dir > 0 && inside.数量 < cap) { inside.添加(p); } 否则 { stay.添加(p); } } waiting[floor] = stay; } 如果 (done == n) { 跳出; } // 5) 한 층 옮긴다. 할 일이 없으면 다음 사람이 올 때까지 건너뛴다 如果 (dir == 0) { now = t[next]; } 否则 { floor = floor + dir; now++; }}控制台.输出(arrive.连接("\n"));