{ }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 " + 모두);