{ }codelper
キューP0351

先に来た人から受け取る傘の貸し出し

学校の玄関に傘の貸し出しスタンドがあり、はじめに傘が u 本立っている。
出来事 n 個が起こった順に与えられる。
want 名前 は、その名前の人が傘を借りに来たことを表す。
スタンドに傘があればすぐに 1 本借りていき、なければ待ち行列のいちばん後ろに並ぶ。
back は、借りられていた傘が 1 本戻ってきたことを表す。
待っている人がいれば、その中でいちばん先に来た人がその傘をすぐに受け取って行列を離れる。
待っている人がいなければ、傘をスタンドに立てる。
出来事ごとに 1 行を出力せよ。
その出来事でだれかが傘を受け取ったならその人の名前を、だれも受け取らなかったなら - を出力する。
最後の行には、まだ待っている人の数とスタンドに立っている傘の数を、空白 1 つで区切って出力せよ。

入力
1 行目に n と u が空白 1 つで区切られて与えられる。
続く n 行に出来事が 1 行に 1 つずつ与えられる。
1 ≤ n ≤ 9,000、0 ≤ u ≤ 9,000。
名前は英小文字 1 〜 10 文字で、別の人が同じ名前のこともある。
back は、借りられてまだ戻っていない傘が 1 本以上あるときだけ与えられる
出力
n + 1 行。
出来事ごとに傘を受け取った人の名前または -、最後の行に待っている人の数とスタンドの傘の数
例 1 · stdin
8 1
want mina
want joon
want sora
back
back
back
want hana
want dan
stdout
mina
-
-
joon
sora
-
hana
-
1 0
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

キュー(先に入れたものが先に出る列)を作る道具は言語ごとに違います。
Python は collections.deque に append で入れ、popleft() で取り出します。
Java は ArrayDeque の addLast・pollFirst、C# は Queue<T> の Enqueue・Dequeue、C++ は std::queue の push・front・pop です。
C++ の pop() は値を返さないので、先に front() で読みます。
JS・TS と C、Craykon にはキューが別にないので、配列(リスト)の後ろに入れ(JS push、Craykon 追加)、先頭の位置を指す数 head だけを 1 つずつ進めます。
落とし穴 1:後ろから取り出すと(Python・JS の pop())スタックになり、いちばん遅く来た人が先に受け取ります。
例の最初の back で joon ではなく sora が出ます。
落とし穴 2:取り出す前に、列が空かどうかを先に確かめます。
空の列から取り出したときに起こることは言語ごとに違います。
Python の popleft() は IndexError で、C# の Dequeue() は InvalidOperationException で止まり、Java の pollFirst() は null を、JS の shift() はエラーなしで undefined を返します。
そのため JS では例の 3 番目の back で undefined が出力され、傘がスタンドに戻らないので hana も受け取れません。
C++ の front() は空のキューでは何が起こるか決まっておらず、Craykon は空のリストの 0 番を読むとエラーで止まります。
落とし穴 3:戻ってきた傘は、待っていた人に渡るか、スタンドに立てられるかのどちらか一方です。
スタンドの数を増やしたうえで待っていた人にも渡すと傘が 1 本増えてしまい、例の dan が存在しない傘を受け取ります。

Pythonmain.py · 23 行
import sysfrom collections import deque lines = sys.stdin.read().split("\n")n, rack = map(int, lines[0].split())waiting = deque()          # 기다리는 사람들: 뒤로 넣고 앞에서 꺼낸다out = []for line in lines[1:n + 1]:    parts = line.split()    if parts[0] == "want":        if rack > 0:            rack -= 1            out.append(parts[1])        else:            waiting.append(parts[1])            out.append("-")    elif waiting:        out.append(waiting.popleft())   # 가장 먼저 온 사람이 받는다    else:        rack += 1                       # 기다리는 사람이 없으면 대여함에 꽂는다        out.append("-")out.append(f"{len(waiting)} {rack}")print("\n".join(out))
JavaScriptmain.js · 26 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [n, u] = lines[0].trim().split(" ").map(Number);let rack = u;// JS에는 큐가 따로 없다. 배열 뒤에 넣고, 맨 앞 자리(head)만 뒤로 옮긴다.const waiting = [];let head = 0;const out = [];for (let i = 1; i <= n; i++) {  const [cmd, name] = lines[i].trim().split(" ");  if (cmd === "want") {    if (rack > 0) {      rack--;      out.push(name);    } else {      waiting.push(name);      out.push("-");    }  } else if (head < waiting.length) {    out.push(waiting[head++]); // 가장 먼저 온 사람이 받는다  } else {    rack++; // 기다리는 사람이 없으면 대여함에 꽂는다    out.push("-");  }}out.push(`${waiting.length - head} ${rack}`);console.log(out.join("\n"));
TypeScriptmain.ts · 28 行
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, u]: number[] = lines[0].trim().split(" ").map(Number);let rack: number = u;// TS에도 큐가 따로 없다. 배열 뒤에 넣고, 맨 앞 자리(head)만 뒤로 옮긴다.const waiting: string[] = [];let head = 0;const out: string[] = [];for (let i = 1; i <= n; i++) {  const [cmd, name]: string[] = lines[i].trim().split(" ");  if (cmd === "want") {    if (rack > 0) {      rack--;      out.push(name);    } else {      waiting.push(name);      out.push("-");    }  } else if (head < waiting.length) {    out.push(waiting[head++]); // 가장 먼저 온 사람이 받는다  } else {    rack++; // 기다리는 사람이 없으면 대여함에 꽂는다    out.push("-");  }}out.push(`${waiting.length - head} ${rack}`);console.log(out.join("\n"));
JavaMain.java · 34 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayDeque; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        String[] first = in.readLine().trim().split(" ");        int n = Integer.parseInt(first[0]);        int rack = Integer.parseInt(first[1]);        ArrayDeque<String> waiting = new ArrayDeque<>();        StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            String[] parts = in.readLine().trim().split(" ");            if (parts[0].equals("want")) {                if (rack > 0) {                    rack--;                    out.append(parts[1]).append('\n');                } else {                    waiting.addLast(parts[1]);                    out.append("-\n");                }            } else if (!waiting.isEmpty()) {                out.append(waiting.pollFirst()).append('\n'); // 가장 먼저 온 사람이 받는다            } else {                rack++; // 기다리는 사람이 없으면 대여함에 꽂는다                out.append("-\n");            }        }        out.append(waiting.size()).append(' ').append(rack);        System.out.println(out);    }}
C#Main.cs · 43 行
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        string[] first = Console.ReadLine().Trim().Split(' ');        int n = int.Parse(first[0]);        int rack = int.Parse(first[1]);        var waiting = new Queue<string>();        var sb = new StringBuilder();        for (int i = 0; i < n; i++)        {            string[] parts = Console.ReadLine().Trim().Split(' ');            if (parts[0] == "want")            {                if (rack > 0)                {                    rack--;                    sb.Append(parts[1]).Append('\n');                }                else                {                    waiting.Enqueue(parts[1]);                    sb.Append("-\n");                }            }            else if (waiting.Count > 0)            {                sb.Append(waiting.Dequeue()).Append('\n'); // 가장 먼저 온 사람이 받는다            }            else            {                rack++; // 기다리는 사람이 없으면 대여함에 꽂는다                sb.Append("-\n");            }        }        sb.Append(waiting.Count).Append(' ').Append(rack).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 35 行
#include <iostream>#include <queue>#include <string>using namespace std; int main() {    ios::sync_with_stdio(false);    cin.tie(nullptr);    int n, rack;    cin >> n >> rack;    queue<string> waiting;    for (int i = 0; i < n; i++) {        string cmd;        cin >> cmd;        if (cmd == "want") {            string name;            cin >> name;            if (rack > 0) {                rack--;                cout << name << '\n';            } else {                waiting.push(name);                cout << "-\n";            }        } else if (!waiting.empty()) {            cout << waiting.front() << '\n'; // 가장 먼저 온 사람이 받는다            waiting.pop();                   // pop()은 값을 돌려주지 않는다        } else {            rack++; // 기다리는 사람이 없으면 대여함에 꽂는다            cout << "-\n";        }    }    cout << waiting.size() << ' ' << rack << '\n';    return 0;}
Cmain.c · 35 行
#include <stdio.h>#include <string.h> #define MAXN 9000 /* 배열로 만든 큐: tail 자리에 넣고 head 자리에서 꺼낸다.   기다리는 사람은 모두 합쳐 n명을 넘지 않으니 MAXN칸이면 된다. */static char waiting[MAXN][11]; int main(void) {    int n, rack;    scanf("%d %d", &n, &rack);    int head = 0, tail = 0;    for (int i = 0; i < n; i++) {        char cmd[8], name[11];        scanf("%7s", cmd);        if (strcmp(cmd, "want") == 0) {            scanf("%10s", name);            if (rack > 0) {                rack--;                printf("%s\n", name);            } else {                strcpy(waiting[tail++], name);                printf("-\n");            }        } else if (head < tail) {            printf("%s\n", waiting[head++]); /* 가장 먼저 온 사람이 받는다 */        } else {            rack++; /* 기다리는 사람이 없으면 대여함에 꽂는다 */            printf("-\n");        }    }    printf("%d %d\n", tail - head, rack);    return 0;}
Craykonmain.cray · 36 行
첫줄 = コンソール.数読み();n = 첫줄[0];rack = 첫줄[1];// 목록으로 만든 큐: 뒤에 넣고, 맨 앞 자리(head)만 뒤로 옮긴다waiting = [];head = 0;繰り返す (i = 0; i < n; i++){    parts = コンソール.行読み().空白除去().分ける();    もし (parts[0] == "want")    {        もし (rack > 0)        {            rack -= 1;            コンソール.書く(parts[1]);        }        でなければ        {            waiting.追加(parts[1]);            コンソール.書く("-");        }    }    でなければ もし (head < waiting.個数)    {        // 가장 먼저 온 사람이 받는다        コンソール.書く(waiting[head]);        head += 1;    }    でなければ    {        // 기다리는 사람이 없으면 대여함에 꽂는다        rack += 1;        コンソール.書く("-");    }}コンソール.書く(waiting.個数 - head + " " + rack);