{ }codelper
定数変数の宣言つなげて出力P0163

シャトルバスの時刻表を作る

会社のシャトルバスの一日の時刻表を作る。
路線の規則は次のとおりで、プログラムでは定数として置く。
- 始発は 06:00 に出る。
- 22:30 までは出発できる(22:30 に出る便もある)。
22:30 より遅い出発はない。
- 通勤時間帯は 07:00 以上 09:00 未満と 17:00 以上 19:00 未満である。
ある便が出た時刻が通勤時間帯の中なら次の便は R 分後に、そうでなければ N 分後に出る。
入力として N と R が与えられる。
出発が一つでもある時(じ)ごとに、早い時から一行に "HH:" を書き、その時の分を早い順に空白一つずつ空けて続けて書く(例:"07: 20 35 50")。
時と分はどちらも二桁で書く(6 時は 06、5 分は 05)。
出発のない時は行を書かない。
最後の行には "total" と一日の出発数を空白一つで区切って出力せよ。

入力
一行に N と R(1 ≤ R ≤ N ≤ 180、整数)
出力
出発のある時ごとに一行 "HH: MM MM …"、最後の行に "total 出発数"
例 1 · stdin
90 30
stdout
06: 00
07: 30
08: 00 30
09: 00
10: 30
12: 00
13: 30
15: 00
16: 30
18: 00 30
19: 00
20: 30
22: 00
total 15
main.py
入力(stdin)

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

$ 準備完了

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

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

定数の書き方は言語ごとに違います。
Python には文法がないので、FIRST = 360 のように大文字の名前で約束するだけです。
JS・TS const、Java static final int、C# const int(配列やタプルは const にできないので static readonly)、C #define FIRST (6 * 60) または const int、C++ constexpr int です。
Craykon には定数がないので、変えないと約束した変数 始発 = 6 * 60; として置きます。
JS の const と Java の final は名前を固定するだけなので、配列の要素を変える RUSH[0][0] = 0 は止めません(TS は readonly、JS は Object.freeze で止めます)。
変数を作る場所も大切です。
今集めている時と分のリストはループの外で作らないと、ループが終わった後に最後の時(22 時)を書けません。
JS・TS(let・const)、Java・C#・C・C++ ではブロック {} の中で作った変数はブロックの外から見えず、Craykon でもブロックの中で初めて入れた変数は外から見えません。
Python はブロックがスコープを作らないので、中で作った変数も外から見えます。
時が変わったときに分のリストを作り直さないと前の時の分がたまり続け、ループの後に最後の時を書かないと 22 時の行が抜けます。
つなげて書くには Python " ".join(分)、JS・TS 分.join(" ")、Java String.join(" ", 分)、C# string.Join(" ", 分)、Craykon 分.つなぐ(" ")。
C には join がないので、"06:" を書いた後、分ごとに前に空白を付けて " 00" のように書きます。
見出しを "06: " と書いたうえでさらに付けると空白が二つになります。
境界も落とし穴です。
通勤時間帯は終わりを含まないので(start <= t && t < end)09:00 に出た便の次は N 分後で、22:30 に出る便は含めます(t <= LAST)。
時と分は %02d、padStart(2, "0")、D2、Craykon 前埋め(2, "0") で二桁にします。

Pythonmain.py · 26 行
# 파이썬에는 상수 문법이 없다: 대문자 이름으로 "바꾸지 않음"을 약속한다FIRST = 6 * 60          # 06:00LAST = 22 * 60 + 30     # 22:30 (이 시각까지 출발할 수 있다)RUSH = ((7 * 60, 9 * 60), (17 * 60, 19 * 60))  # [시작, 끝) — 끝 시각은 들어가지 않는다  def is_rush(t):    return any(start <= t < end for start, end in RUSH)  normal, rush = map(int, input().split())hour = -1      # 지금 모으는 시(반복문 밖에서 만든다)minutes = []   # 그 시의 분들total = 0t = FIRSTwhile t <= LAST:    if t // 60 != hour:        if minutes:            print(f"{hour:02d}: " + " ".join(minutes))        hour = t // 60        minutes = []    minutes.append(f"{t % 60:02d}")    total += 1    t += rush if is_rush(t) else normalprint(f"{hour:02d}: " + " ".join(minutes))  # 마지막 시도 잊지 않는다print("total", total)
JavaScriptmain.js · 25 行
// const는 다시 넣을 수 없는 이름이다(배열 안의 칸은 바꿀 수 있다)const FIRST = 6 * 60;const LAST = 22 * 60 + 30;const RUSH = [[7 * 60, 9 * 60], [17 * 60, 19 * 60]]; // [시작, 끝) const isRush = (t) => RUSH.some(([start, end]) => start <= t && t < end);const two = (x) => String(x).padStart(2, "0"); const [normal, rush] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const out = [];let hour = -1; // 반복문 밖에서 let으로 만들어야 반복이 끝난 뒤에도 쓴다let minutes = [];let total = 0;for (let t = FIRST; t <= LAST; t += isRush(t) ? rush : normal) {  if (Math.floor(t / 60) !== hour) {    if (minutes.length > 0) out.push(`${two(hour)}: ${minutes.join(" ")}`);    hour = Math.floor(t / 60);    minutes = [];  }  minutes.push(two(t % 60));  total++;}out.push(`${two(hour)}: ${minutes.join(" ")}`);out.push(`total ${total}`);console.log(out.join("\n"));
TypeScriptmain.ts · 30 行
import { readFileSync } from "node:fs";const FIRST = 6 * 60;const LAST = 22 * 60 + 30;// readonly 튜플: 타입 검사기가 칸을 바꾸지 못하게 막는다const RUSH: readonly (readonly [number, number])[] = [[7 * 60, 9 * 60], [17 * 60, 19 * 60]]; // [시작, 끝) function isRush(t: number): boolean {  return RUSH.some(([start, end]) => start <= t && t < end);}function two(x: number): string {  return String(x).padStart(2, "0");} const [normal, rush]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const out: string[] = [];let hour: number = -1;let minutes: string[] = [];let total = 0;for (let t = FIRST; t <= LAST; t += isRush(t) ? rush : normal) {  if (Math.floor(t / 60) !== hour) {    if (minutes.length > 0) out.push(`${two(hour)}: ${minutes.join(" ")}`);    hour = Math.floor(t / 60);    minutes = [];  }  minutes.push(two(t % 60));  total++;}out.push(`${two(hour)}: ${minutes.join(" ")}`);out.push(`total ${total}`);console.log(out.join("\n"));
JavaMain.java · 37 行
import java.util.ArrayList;import java.util.List;import java.util.Scanner; public class Main {    // static final: 한 번 넣으면 바꿀 수 없다(배열이면 이름만 고정이고 칸은 바뀐다)    static final int FIRST = 6 * 60;    static final int LAST = 22 * 60 + 30;    static final int[][] RUSH = {{7 * 60, 9 * 60}, {17 * 60, 19 * 60}}; // [시작, 끝)     static boolean isRush(int t) {        for (int[] w : RUSH)            if (w[0] <= t && t < w[1]) return true;        return false;    }     public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int normal = sc.nextInt(), rush = sc.nextInt();        StringBuilder out = new StringBuilder();        int hour = -1; // 반복문 밖에서 만든다        List<String> minutes = new ArrayList<>();        int total = 0;        for (int t = FIRST; t <= LAST; t += isRush(t) ? rush : normal) {            if (t / 60 != hour) {                if (!minutes.isEmpty()) out.append(String.format("%02d: ", hour)).append(String.join(" ", minutes)).append('\n');                hour = t / 60;                minutes = new ArrayList<>();            }            minutes.add(String.format("%02d", t % 60));            total++;        }        out.append(String.format("%02d: ", hour)).append(String.join(" ", minutes)).append('\n');        out.append("total ").append(total).append('\n');        System.out.print(out);    }}
C#Main.cs · 42 行
using System;using System.Collections.Generic;using System.Text; class Program{    // const는 컴파일할 때 정해지는 값만 된다. 배열은 static readonly로    const int First = 6 * 60;    const int Last = 22 * 60 + 30;    static readonly (int Start, int End)[] Rush = { (7 * 60, 9 * 60), (17 * 60, 19 * 60) }; // [시작, 끝)     static bool IsRush(int t)    {        foreach (var w in Rush)            if (w.Start <= t && t < w.End) return true;        return false;    }     static void Main()    {        string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int normal = int.Parse(p[0]), rush = int.Parse(p[1]);        var sb = new StringBuilder();        int hour = -1; // 반복문 밖에서 만든다        var minutes = new List<string>();        int total = 0;        for (int t = First; t <= Last; t += IsRush(t) ? rush : normal)        {            if (t / 60 != hour)            {                if (minutes.Count > 0) sb.Append($"{hour:D2}: ").Append(string.Join(" ", minutes)).Append('\n');                hour = t / 60;                minutes = new List<string>();            }            minutes.Add($"{t % 60:D2}");            total++;        }        sb.Append($"{hour:D2}: ").Append(string.Join(" ", minutes)).Append('\n');        sb.Append("total ").Append(total).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 42 行
#include <array>#include <cstdio>#include <iostream>#include <string>#include <utility> // constexpr: 컴파일할 때 값이 정해지는 상수constexpr int FIRST = 6 * 60;constexpr int LAST = 22 * 60 + 30;constexpr std::array<std::pair<int, int>, 2> RUSH{{{7 * 60, 9 * 60}, {17 * 60, 19 * 60}}}; // [시작, 끝) bool isRush(int t) {    for (const auto& [start, end] : RUSH)        if (start <= t && t < end) return true;    return false;} std::string two(int x) {    char buf[4];    std::snprintf(buf, sizeof buf, "%02d", x);    return buf;} int main() {    int normal, rush;    std::cin >> normal >> rush;    std::string out, line;    int hour = -1; // 반복문 밖에서 만든다    int total = 0;    for (int t = FIRST; t <= LAST; t += isRush(t) ? rush : normal) {        if (t / 60 != hour) {            if (!line.empty()) out += line + '\n';            hour = t / 60;            line = two(hour) + ":";        }        line += " " + two(t % 60);        total++;    }    out += line + '\n';    out += "total " + std::to_string(total) + '\n';    std::cout << out;}
Cmain.c · 30 行
#include <stdio.h> /* #define은 컴파일 전에 글자 그대로 바꿔 넣는다(타입이 없다) */#define FIRST (6 * 60)#define LAST (22 * 60 + 30)static const int RUSH[2][2] = {{7 * 60, 9 * 60}, {17 * 60, 19 * 60}}; /* [시작, 끝) */ static int is_rush(int t) {    for (int i = 0; i < 2; i++)        if (RUSH[i][0] <= t && t < RUSH[i][1]) return 1;    return 0;} int main(void) {    int normal, rush;    scanf("%d %d", &normal, &rush);    int hour = -1; /* 반복문 밖에서 만든다 */    int total = 0;    for (int t = FIRST; t <= LAST; t += is_rush(t) ? rush : normal) {        if (t / 60 != hour) {            if (hour != -1) putchar('\n');            hour = t / 60;            printf("%02d:", hour); /* 사이 빈칸은 분마다 앞에 붙인다 */        }        printf(" %02d", t % 60);        total++;    }    printf("\ntotal %d\n", total);    return 0;}
Craykonmain.cray · 55 行
// 크레이콘에는 상수가 없다: 바꾸지 않기로 약속한 변수로 둔다첫차 = 6 * 60;막차 = 22 * 60 + 30;붐빔시작 = [7 * 60, 17 * 60];붐빔끝 = [9 * 60, 19 * 60]; 붐비나(t){    繰り返す (i = 0; i < 2; i++)    {        もし (붐빔시작[i] <= t && t < 붐빔끝[i])        {            返す 真;        }    }    返す 偽;} 두자리(x){    返す ("" + x).前埋め(2, "0");} 간격들 = コンソール.数読み();보통 = 간격들[0];붐빌때 = 간격들[1];// 블록 안에서 처음 넣은 변수는 블록 밖에서 안 보인다: 반복 전에 만든다시 = -1;분들 = [];모두 = 0;t = 첫차;間 (t <= 막차){    もし (数学.商(t, 60) != 시)    {        もし (분들.個数 > 0)        {            コンソール.書く(두자리(시) + ": " + 분들.つなぐ(" "));        }        시 = 数学.商(t, 60);        분들 = [];    }    분들.追加(두자리(t % 60));    모두 += 1;    もし (붐비나(t))    {        t += 붐빌때;    }    でなければ    {        t += 보통;    }}コンソール.書く(두자리(시) + ": " + 분들.つなぐ(" "));コンソール.書く("total " + 모두);