회사 셔틀버스의 하루 시간표를 만든다.
노선 규칙은 다음과 같고, 풀이에서는 상수로 둔다.
- 첫차는 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"과 하루 출발 수를 빈칸 하나로 띄워 출력하라.
실행하면 이 줄들이 차례로 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 " + 모두);