{ }codelper
判定関数引数戻り値P0149

会議室予約の時間チェッカー

会議室の予約リクエストが "HH:MM-HH:MM" の形(開始時刻-終了時刻)の文字列で届く。
一行目にリクエストの数 n が、続く n 行にリクエストが一つずつ与えられる。
リクエストごとに次の六つの規則を 1 番から順に調べる。
1.
形:ちょうど 11 文字で、3 文字目と 9 文字目は ':'、6 文字目は '-'、残りの 8 文字はすべて数字(0~9)である。
2.
時刻:二つの時刻とも、時(HH)が 00 ~ 23、分(MM)が 00 ~ 59 である。
3.
15 分単位:二つの時刻とも、分が 00、15、30、45 のいずれかである。
4.
順序:開始時刻が終了時刻より早い。
5.
営業時間:開始時刻が 09:00 以降(09:00 を含む)で、終了時刻が 18:00 以前(18:00 を含む)である。
6.
長さ:予約の長さが 3 時間(180 分)以下である。
リクエストごとに最初に破った規則の番号を一行に出力し、すべて守っていれば 0 を出力する。
最後の行にすべての規則を守ったリクエストの数を出力する。
「数字か」「形が合っているか」「正しい時刻か」のように真偽を返す小さな関数と、最初に破った規則の番号を返す関数に分けて作る。

入力
1 ≤ n ≤ 100。
リクエストは空白のない文字(ASCII コード 33 ~ 126)1 ~ 20 個からなる文字列である
出力
n + 1 行。
リクエストごとに 0 ~ 6 のいずれか、最後の行にすべて守ったリクエストの数
例 1 · stdin
8
10:00-11:30
9:00-10:00
09:00-10:60
13:10-14:00
15:00-15:00
08:45-10:00
12:00-15:15
15:00-18:00
stdout
0
1
2
3
4
5
6
0
2
main.py
入力(stdin)

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

$ 準備完了

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

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

真偽を返す小さな関数を集めて大きな検査を作る問題です。
真偽の型は Python bool(True/False)、JS・TS boolean、Java boolean、C# bool、C++ bool、C は stdbool.h の bool(それ以前は int の 0/1)、Craykon 真/偽(韓国語 참/거짓)です。
長さを先に聞けば s[2] が安全です。
&&・and・|| は前で答えが決まると後ろを見ないので、長さが違えば文字を読まずに終わります。
落とし穴その一:順番を入れ替えて s[2] から見ると、短い文字列で Python は IndexError、Java は StringIndexOutOfBoundsException、C# は IndexOutOfRangeException で止まり、JS は undefined、C は文字列の終わりを越えて読みます。
落とし穴その二:数字かどうかを変換関数に任せてはいけません。
Python の int("+9")・int("-1") は 9 と -1 を返し、JS の parseInt("1a") は先頭の 1 だけを読み、C の sscanf("%d:%d-%d:%d") も +9 を受け付けます。
文字ごとに '0' <= ch <= '9' を聞く関数を別に作ります。
Craykon も ch >= "0" && ch <= "9" のように文字列の大小比較で書きます。
落とし穴その三:18:00 に終わる予約とちょうど 180 分の予約は許されるので <= です。

Pythonmain.py · 46 行
def is_digit(ch):    return "0" <= ch <= "9"   # 아스키 숫자만(str.isdigit은 다른 숫자 글자도 참)  def well_formed(s):    """규칙 1: HH:MM-HH:MM 꼴인가. 길이부터 물어야 s[2]가 안전하다."""    if len(s) != 11 or s[2] != ":" or s[5] != "-" or s[8] != ":":        return False    return all(is_digit(s[i]) for i in (0, 1, 3, 4, 6, 7, 9, 10))  def valid_clock(h, m):    return 0 <= h <= 23 and 0 <= m <= 59  def on_grid(m):    return m % 15 == 0  def first_broken(s):    """처음 어긴 규칙 번호, 모두 지키면 0."""    if not well_formed(s):        return 1    h1, m1, h2, m2 = int(s[0:2]), int(s[3:5]), int(s[6:8]), int(s[9:11])    if not (valid_clock(h1, m1) and valid_clock(h2, m2)):        return 2    if not (on_grid(m1) and on_grid(m2)):        return 3    start, end = h1 * 60 + m1, h2 * 60 + m2    if not start < end:        return 4    if not (start >= 9 * 60 and end <= 18 * 60):        return 5    if end - start > 180:        return 6    return 0  n = int(input())passed = 0for _ in range(n):    r = first_broken(input().strip())    print(r)    if r == 0:        passed += 1print(passed)
JavaScriptmain.js · 31 行
const lines = require("fs").readFileSync(0, "utf8").split("\n"); const isDigit = (ch) => ch >= "0" && ch <= "9"; // 규칙 1: HH:MM-HH:MM 꼴인가function wellFormed(s) {  if (s.length !== 11 || s[2] !== ":" || s[5] !== "-" || s[8] !== ":") return false;  return [0, 1, 3, 4, 6, 7, 9, 10].every((i) => isDigit(s[i]));} const validClock = (h, m) => h >= 0 && h <= 23 && m >= 0 && m <= 59;const onGrid = (m) => m % 15 === 0; // 처음 어긴 규칙 번호, 모두 지키면 0function firstBroken(s) {  if (!wellFormed(s)) return 1;  const [h1, m1, h2, m2] = [0, 3, 6, 9].map((i) => Number(s.slice(i, i + 2)));  if (!(validClock(h1, m1) && validClock(h2, m2))) return 2;  if (!(onGrid(m1) && onGrid(m2))) return 3;  const start = h1 * 60 + m1;  const end = h2 * 60 + m2;  if (!(start < end)) return 4;  if (!(start >= 9 * 60 && end <= 18 * 60)) return 5;  if (end - start > 180) return 6;  return 0;} const n = Number(lines[0]);const out = lines.slice(1, n + 1).map((line) => firstBroken(line.trim()));out.push(out.filter((r) => r === 0).length);console.log(out.join("\n"));
TypeScriptmain.ts · 32 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n"); const isDigit = (ch: string): boolean => ch >= "0" && ch <= "9"; // 규칙 1: HH:MM-HH:MM 꼴인가function wellFormed(s: string): boolean {  if (s.length !== 11 || s[2] !== ":" || s[5] !== "-" || s[8] !== ":") return false;  return [0, 1, 3, 4, 6, 7, 9, 10].every((i) => isDigit(s[i]));} const validClock = (h: number, m: number): boolean => h >= 0 && h <= 23 && m >= 0 && m <= 59;const onGrid = (m: number): boolean => m % 15 === 0; // 처음 어긴 규칙 번호, 모두 지키면 0function firstBroken(s: string): number {  if (!wellFormed(s)) return 1;  const [h1, m1, h2, m2] = [0, 3, 6, 9].map((i) => Number(s.slice(i, i + 2)));  if (!(validClock(h1, m1) && validClock(h2, m2))) return 2;  if (!(onGrid(m1) && onGrid(m2))) return 3;  const start = h1 * 60 + m1;  const end = h2 * 60 + m2;  if (!(start < end)) return 4;  if (!(start >= 9 * 60 && end <= 18 * 60)) return 5;  if (end - start > 180) return 6;  return 0;} const n = Number(lines[0]);const out: number[] = lines.slice(1, n + 1).map((line) => firstBroken(line.trim()));out.push(out.filter((r) => r === 0).length);console.log(out.join("\n"));
JavaMain.java · 55 行
import java.io.*; public class Main {    static boolean isDigit(char ch) {        return ch >= '0' && ch <= '9'; // Character.isDigit은 다른 나라 숫자도 참    }     // 규칙 1: HH:MM-HH:MM 꼴인가. 길이부터 물어야 charAt(2)가 안전하다    static boolean wellFormed(String s) {        if (s.length() != 11 || s.charAt(2) != ':' || s.charAt(5) != '-' || s.charAt(8) != ':') return false;        for (int i : new int[] {0, 1, 3, 4, 6, 7, 9, 10}) {            if (!isDigit(s.charAt(i))) return false;        }        return true;    }     static boolean validClock(int h, int m) {        return h >= 0 && h <= 23 && m >= 0 && m <= 59;    }     static boolean onGrid(int m) {        return m % 15 == 0;    }     static int two(String s, int i) {        return (s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0');    }     // 처음 어긴 규칙 번호, 모두 지키면 0    static int firstBroken(String s) {        if (!wellFormed(s)) return 1;        int h1 = two(s, 0), m1 = two(s, 3), h2 = two(s, 6), m2 = two(s, 9);        if (!(validClock(h1, m1) && validClock(h2, m2))) return 2;        if (!(onGrid(m1) && onGrid(m2))) return 3;        int start = h1 * 60 + m1, end = h2 * 60 + m2;        if (!(start < end)) return 4;        if (!(start >= 9 * 60 && end <= 18 * 60)) return 5;        if (end - start > 180) return 6;        return 0;    }     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        StringBuilder out = new StringBuilder();        int passed = 0;        for (int i = 0; i < n; i++) {            int r = firstBroken(br.readLine().trim());            out.append(r).append('\n');            if (r == 0) passed++;        }        out.append(passed).append('\n');        System.out.print(out);    }}
C#Main.cs · 49 行
using System;using System.Linq;using System.Text; class Program{    static bool IsDigit(char ch) => ch >= '0' && ch <= '9'; // char.IsDigit은 다른 나라 숫자도 참     // 규칙 1: HH:MM-HH:MM 꼴인가. 길이부터 물어야 s[2]가 안전하다    static bool WellFormed(string s)    {        if (s.Length != 11 || s[2] != ':' || s[5] != '-' || s[8] != ':') return false;        return new[] { 0, 1, 3, 4, 6, 7, 9, 10 }.All(i => IsDigit(s[i]));    }     static bool ValidClock(int h, int m) => h >= 0 && h <= 23 && m >= 0 && m <= 59;     static bool OnGrid(int m) => m % 15 == 0;     // 처음 어긴 규칙 번호, 모두 지키면 0    static int FirstBroken(string s)    {        if (!WellFormed(s)) return 1;        int h1 = int.Parse(s.Substring(0, 2)), m1 = int.Parse(s.Substring(3, 2));        int h2 = int.Parse(s.Substring(6, 2)), m2 = int.Parse(s.Substring(9, 2));        if (!(ValidClock(h1, m1) && ValidClock(h2, m2))) return 2;        if (!(OnGrid(m1) && OnGrid(m2))) return 3;        int start = h1 * 60 + m1, end = h2 * 60 + m2;        if (!(start < end)) return 4;        if (!(start >= 9 * 60 && end <= 18 * 60)) return 5;        if (end - start > 180) return 6;        return 0;    }     static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        var sb = new StringBuilder();        int passed = 0;        for (int i = 0; i < n; i++)        {            int r = FirstBroken(Console.ReadLine().Trim());            sb.Append(r).Append('\n');            if (r == 0) passed++;        }        sb.Append(passed).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 44 行
#include <iostream>#include <string> bool is_digit(char ch) { return ch >= '0' && ch <= '9'; } // 규칙 1: HH:MM-HH:MM 꼴인가. 길이부터 물어야 s[2]가 안전하다bool well_formed(const std::string& s) {    if (s.size() != 11 || s[2] != ':' || s[5] != '-' || s[8] != ':') return false;    for (int i : {0, 1, 3, 4, 6, 7, 9, 10})        if (!is_digit(s[i])) return false;    return true;} bool valid_clock(int h, int m) { return h >= 0 && h <= 23 && m >= 0 && m <= 59; } bool on_grid(int m) { return m % 15 == 0; } int two(const std::string& s, int i) { return (s[i] - '0') * 10 + (s[i + 1] - '0'); } // 처음 어긴 규칙 번호, 모두 지키면 0int first_broken(const std::string& s) {    if (!well_formed(s)) return 1;    int h1 = two(s, 0), m1 = two(s, 3), h2 = two(s, 6), m2 = two(s, 9);    if (!(valid_clock(h1, m1) && valid_clock(h2, m2))) return 2;    if (!(on_grid(m1) && on_grid(m2))) return 3;    int start = h1 * 60 + m1, end = h2 * 60 + m2;    if (!(start < end)) return 4;    if (!(start >= 9 * 60 && end <= 18 * 60)) return 5;    if (end - start > 180) return 6;    return 0;} int main() {    int n, passed = 0;    std::cin >> n;    for (int i = 0; i < n; i++) {        std::string s;        std::cin >> s; // 빈칸 없는 문자열        int r = first_broken(s);        std::cout << r << "\n";        if (r == 0) passed++;    }    std::cout << passed << "\n";}
Cmain.c · 47 行
#include <stdbool.h>#include <stdio.h>#include <string.h> static bool is_digit(char ch) { return ch >= '0' && ch <= '9'; } /* 규칙 1: HH:MM-HH:MM 꼴인가. 길이부터 물어야 s[2]가 안전하다 */static bool well_formed(const char *s) {    if (strlen(s) != 11 || s[2] != ':' || s[5] != '-' || s[8] != ':') return false;    const int at[] = {0, 1, 3, 4, 6, 7, 9, 10};    for (int i = 0; i < 8; i++)        if (!is_digit(s[at[i]])) return false;    return true;} static bool valid_clock(int h, int m) { return h >= 0 && h <= 23 && m >= 0 && m <= 59; } static bool on_grid(int m) { return m % 15 == 0; } static int two(const char *s, int i) { return (s[i] - '0') * 10 + (s[i + 1] - '0'); } /* 처음 어긴 규칙 번호, 모두 지키면 0 */static int first_broken(const char *s) {    if (!well_formed(s)) return 1;    int h1 = two(s, 0), m1 = two(s, 3), h2 = two(s, 6), m2 = two(s, 9);    if (!(valid_clock(h1, m1) && valid_clock(h2, m2))) return 2;    if (!(on_grid(m1) && on_grid(m2))) return 3;    int start = h1 * 60 + m1, end = h2 * 60 + m2;    if (!(start < end)) return 4;    if (!(start >= 9 * 60 && end <= 18 * 60)) return 5;    if (end - start > 180) return 6;    return 0;} int main(void) {    int n, passed = 0;    scanf("%d", &n);    for (int i = 0; i < n; i++) {        char s[32];        scanf("%31s", s); /* 빈칸 없는 문자열, 많아야 20글자 */        int r = first_broken(s);        printf("%d\n", r);        if (r == 0) passed++;    }    printf("%d\n", passed);    return 0;}
Craykonmain.cray · 80 行
숫자인가(ch){    返す ch >= "0" && ch <= "9";} // 규칙 1: HH:MM-HH:MM 꼴인가. 길이부터 물어야 s[2]가 안전하다꼴이맞나(s){    もし (s.長さ != 11 || s[2] != ":" || s[5] != "-" || s[8] != ":")    {        返す 偽;    }    それぞれ (i の中 [0, 1, 3, 4, 6, 7, 9, 10])    {        もし (!숫자인가(s[i]))        {            返す 偽;        }    }    返す 真;} 시각인가(h, m){    返す h >= 0 && h <= 23 && m >= 0 && m <= 59;} 십오분단위인가(m){    返す m % 15 == 0;} // 처음 어긴 규칙 번호, 모두 지키면 0처음어긴규칙(s){    もし (!꼴이맞나(s))    {        返す 1;    }    h1 = s.切り出す(0, 2).数に();    m1 = s.切り出す(3, 2).数に();    h2 = s.切り出す(6, 2).数に();    m2 = s.切り出す(9, 2).数に();    もし (!(시각인가(h1, m1) && 시각인가(h2, m2)))    {        返す 2;    }    もし (!(십오분단위인가(m1) && 십오분단위인가(m2)))    {        返す 3;    }    start = h1 * 60 + m1;    end = h2 * 60 + m2;    もし (!(start < end))    {        返す 4;    }    もし (!(start >= 9 * 60 && end <= 18 * 60))    {        返す 5;    }    もし (end - start > 180)    {        返す 6;    }    返す 0;} n = コンソール.行読み().数に();passed = 0;繰り返す (i = 0; i < n; i++){    r = 처음어긴규칙(コンソール.行読み().空白除去());    コンソール.書く(r);    もし (r == 0)    {        passed++;    }}コンソール.書く(passed);