{ }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()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 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예요.
크레이콘에는 상수가 없어서 바꾸지 않기로 약속한 변수 첫차 = 6 * 60;으로 둬요.
JS const와 Java final은 이름만 묶기 때문에 배열 칸을 바꾸는 RUSH[0][0] = 0은 막지 않아요(TS는 readonly, JS는 Object.freeze로 막아요).
변수를 만드는 자리도 중요해요.
지금 모으는 시와 분 목록은 반복문 밖에서 만들어야 반복이 끝난 뒤 마지막 시(22시)를 쓸 수 있어요.
JS·TS let·const, Java·C#·C·C++은 블록 {} 안에서 만든 변수가 블록 밖에서 안 보이고, 크레이콘도 블록 안에서 처음 넣은 변수는 밖에서 안 보여요.
Python은 블록이 범위를 만들지 않아서 안에서 만든 변수도 밖에서 보여요.
시가 바뀔 때 분 목록을 새로 만들지 않으면 앞 시의 분이 계속 쌓이고, 반복 뒤에 마지막 시를 쓰지 않으면 22시 줄이 빠져요.
이어서 쓰기는 Python " ".join(분들), JS·TS 분들.join(" "), Java String.join(" ", 분들), C# string.Join(" ", 분들), 크레이콘 분들.잇기(" ")예요.
C에는 join이 없어서 "06:"을 쓴 뒤 분마다 앞에 빈칸을 붙여 " 00"처럼 써요.
머리를 "06: "로 쓰고 또 붙이면 빈칸이 둘이 돼요.
경계도 함정이에요.
출퇴근 시간은 끝을 넣지 않으니(start <= t && t < end) 09:00에 떠난 차 다음은 N분 뒤이고, 22:30에 떠나는 차는 넣어요(t <= LAST).
시와 분은 %02d, padStart(2, "0"), D2, 크레이콘 앞채우기(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 " + 모두);