{ }codelper
끝 표시까지 반복절댓값P0235

0층이 없는 승강기 운행 기록

지하 9층부터 지상 60층까지 있는 건물의 승강기 기록을 정리한다. 지상 층은 1부터 60까지, 지하 층은 지하 1층이 -1, 지하 9층이 -9처럼 음수로 쓴다. 이 건물에는 0층이 없어서, 지상 1층 바로 아래가 지하 1층이다. 승강기는 처음에 1층에 있다. 입력은 한 줄에 정수 하나씩이고, 승강기가 차례로 가야 할 층이 주어진다. 0이 나오면 기록이 끝났다는 표시다. 0 자체는 층이 아니며, 0 뒤에 줄이 더 있어도 모두 무시한다. 가야 할 층이 지금 있는 층과 같으면 아무 일도 하지 않는다. 다르면 승강기가 그 층으로 움직이고, 이것을 정차 한 번으로 센다. 한 번 움직인 거리는 그 사이의 층 간격 수다: 1층에서 3층은 2, 1층에서 -1층은 1, 2층에서 -2층은 3이다. 움직일 때마다 방향은 올라감이나 내려감이다. 어떤 움직임의 방향이 바로 앞 움직임의 방향과 다르면 방향이 한 번 바뀐 것으로 센다(첫 움직임은 세지 않고, 무시한 요청은 움직임이 아니다). 정차 횟수, 움직인 거리의 합, 방향이 바뀐 횟수를 빈칸 하나씩으로 띄워 한 줄에 출력하라. 0이 맨 처음에 나오면 0 0 0을 출력한다.

입력
0 앞의 줄은 0 ~ 10,000줄이고 각각 -9 이상 60 이하이며 0이 아닌 정수다, 0은 반드시 나온다, 0 뒤의 줄은 0 ~ 10,000줄이고 각각 -9 이상 60 이하의 정수다(0일 수도 있다)
출력
정차 횟수, 움직인 거리의 합, 방향이 바뀐 횟수 한 줄
예시 1 · stdin
5
5
-2
3
1
0
7
0
9
stdout
4 16 3
예시 2 · stdin
1
-1
1
-1
0
stdout
3 3 2
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

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

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

끝 표시(센티널)까지 도는 반복은 '읽고, 끝 표시인지 묻고, 처리하고, 다시 읽는' 차례를 지켜야 해요.
C while (scanf("%d", &x) == 1 && x != 0), C++ while (std::cin >> x && x != 0), Java while ((x = sc.nextInt()) != 0), C# while ((x = int.Parse(Console.ReadLine())) != 0)는 읽기와 묻기를 조건 한 줄에 넣어요.
Python은 while True:로 돌며 읽은 뒤 if x == 0: break로 빠져나가요.
JS·TS는 입력 전체를 줄로 나눠 for (const line of lines)로 돌다가 0에서 break해요.
크레이콘은 반복 앞에서 한 번 읽고, 동안 (x != 0) 안의 맨 끝에서 다시 읽어요.
do { 읽고 처리 } while (x != 0)처럼 처리부터 하면 끝 표시 0까지 층으로 다뤄서 승강기가 없는 0층으로 가요.
입력 끝까지 읽으면서 0만 건너뛰는 것도 틀려요.
0 뒤에 남은 줄까지 처리하게 돼요.
크레이콘 콘솔.줄읽기()는 문자열 "0"을 주고 "0"과 수 0은 같지 않아서, 수로변환()을 하지 않고 0과 비교하면 끝 표시를 지나쳐 입력 끝의 빈값에서 멈춰요.
같은 층 요청은 Python·JS·TS·Java·C#·C·C++에서 continue로 넘기면 돼요.
읽기가 반복 조건 안이나 반복 맨 앞에 있어서 다음 줄을 읽게 되기 때문이에요.
크레이콘처럼 다시 읽는 줄이 반복 맨 끝에 있으면 건너뛰기가 그 줄까지 건너뛰어 같은 값을 끝없이 돌다가 '너무 오래 걸려서' 오류로 멈춰요.
그래서 크레이콘 풀이는 만약 (target != floor) 안에 처리를 넣고, 다시 읽는 줄은 그 블록 바깥에 둬요.
거리는 Python abs, JS·TS·Java Math.abs, C# Math.Abs, C abs(<stdlib.h>), C++ std::abs(<cstdlib>), 크레이콘 수학.절댓값으로 구하고, 두 층의 부호가 다르면(한쪽이 지상, 한쪽이 지하) 없는 0층 몫으로 1을 빼요.
방향은 '바로 앞 움직임'과 비교하니 같은 층 요청에서 기억한 방향을 지우면 안 돼요.

Pythonmain.py · 20 줄
floor = 1stops = distance = turns = 0last_dir = 0  # 1이면 올라감, -1이면 내려감, 0이면 아직 움직이지 않음while True:    target = int(input())    if target == 0:  # 끝 표시: 0 뒤의 줄은 읽지 않는다        break    if target == floor:        continue  # 같은 층: 정차도 아니고 방향도 그대로    gap = abs(target - floor)    if (floor > 0) != (target > 0):        gap -= 1  # 지상과 지하 사이에는 0층이 없다    d = 1 if target > floor else -1    if last_dir != 0 and d != last_dir:        turns += 1    stops += 1    distance += gap    last_dir = d    floor = targetprint(stops, distance, turns)
JavaScriptmain.js · 20 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");let floor = 1;let stops = 0;let distance = 0;let turns = 0;let lastDir = 0; // 1이면 올라감, -1이면 내려감, 0이면 아직 움직이지 않음for (const line of lines) {  const target = Number(line);  if (target === 0) break; // 끝 표시: 뒤의 줄은 보지 않는다  if (target === floor) continue; // 같은 층: 정차도 아니고 방향도 그대로  let gap = Math.abs(target - floor);  if (floor > 0 !== target > 0) gap -= 1; // 지상과 지하 사이에는 0층이 없다  const d = target > floor ? 1 : -1;  if (lastDir !== 0 && d !== lastDir) turns++;  stops++;  distance += gap;  lastDir = d;  floor = target;}console.log(`${stops} ${distance} ${turns}`);
TypeScriptmain.ts · 21 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");let floor = 1;let stops = 0;let distance = 0;let turns = 0;let lastDir = 0; // 1이면 올라감, -1이면 내려감, 0이면 아직 움직이지 않음for (const line of lines) {  const target = Number(line);  if (target === 0) break; // 끝 표시: 뒤의 줄은 보지 않는다  if (target === floor) continue; // 같은 층: 정차도 아니고 방향도 그대로  let gap = Math.abs(target - floor);  if (floor > 0 !== target > 0) gap -= 1; // 지상과 지하 사이에는 0층이 없다  const d = target > floor ? 1 : -1;  if (lastDir !== 0 && d !== lastDir) turns++;  stops++;  distance += gap;  lastDir = d;  floor = target;}console.log(`${stops} ${distance} ${turns}`);
JavaMain.java · 23 줄
import java.util.Scanner; public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int floor = 1, stops = 0, distance = 0, turns = 0;        int lastDir = 0; // 1이면 올라감, -1이면 내려감, 0이면 아직 움직이지 않음        int target;        // 끝 표시 0이 나오면 멈춘다: 0 뒤의 줄은 읽지 않는다        while ((target = sc.nextInt()) != 0) {            if (target == floor) continue; // 같은 층: 정차도 아니고 방향도 그대로            int gap = Math.abs(target - floor);            if ((floor > 0) != (target > 0)) gap--; // 지상과 지하 사이에는 0층이 없다            int d = target > floor ? 1 : -1;            if (lastDir != 0 && d != lastDir) turns++;            stops++;            distance += gap;            lastDir = d;            floor = target;        }        System.out.println(stops + " " + distance + " " + turns);    }}
C#Main.cs · 25 줄
using System; class Program{    static void Main()    {        int floor = 1, stops = 0, distance = 0, turns = 0;        int lastDir = 0; // 1이면 올라감, -1이면 내려감, 0이면 아직 움직이지 않음        int target;        // 끝 표시 0이 나오면 멈춘다: 0 뒤의 줄은 읽지 않는다        while ((target = int.Parse(Console.ReadLine())) != 0)        {            if (target == floor) continue; // 같은 층: 정차도 아니고 방향도 그대로            int gap = Math.Abs(target - floor);            if ((floor > 0) != (target > 0)) gap--; // 지상과 지하 사이에는 0층이 없다            int d = target > floor ? 1 : -1;            if (lastDir != 0 && d != lastDir) turns++;            stops++;            distance += gap;            lastDir = d;            floor = target;        }        Console.WriteLine($"{stops} {distance} {turns}");    }}
C++main.cpp · 21 줄
#include <cstdlib>#include <iostream> int main() {    int floor = 1, stops = 0, distance = 0, turns = 0;    int lastDir = 0; // 1이면 올라감, -1이면 내려감, 0이면 아직 움직이지 않음    int target;    // 끝 표시 0이 나오면 멈춘다: 0 뒤의 줄은 읽지 않는다    while (std::cin >> target && target != 0) {        if (target == floor) continue; // 같은 층: 정차도 아니고 방향도 그대로        int gap = std::abs(target - floor);        if ((floor > 0) != (target > 0)) gap--; // 지상과 지하 사이에는 0층이 없다        int d = target > floor ? 1 : -1;        if (lastDir != 0 && d != lastDir) turns++;        stops++;        distance += gap;        lastDir = d;        floor = target;    }    std::cout << stops << ' ' << distance << ' ' << turns << '\n';}
Cmain.c · 22 줄
#include <stdio.h>#include <stdlib.h> int main(void) {    int floor = 1, stops = 0, distance = 0, turns = 0;    int last_dir = 0; /* 1이면 올라감, -1이면 내려감, 0이면 아직 움직이지 않음 */    int target;    /* 끝 표시 0이 나오면 멈춘다: 0 뒤의 줄은 읽지 않는다 */    while (scanf("%d", &target) == 1 && target != 0) {        if (target == floor) continue; /* 같은 층: 정차도 아니고 방향도 그대로 */        int gap = abs(target - floor);        if ((floor > 0) != (target > 0)) gap--; /* 지상과 지하 사이에는 0층이 없다 */        int d = target > floor ? 1 : -1;        if (last_dir != 0 && d != last_dir) turns++;        stops++;        distance += gap;        last_dir = d;        floor = target;    }    printf("%d %d %d\n", stops, distance, turns);    return 0;}
Craykonmain.cray · 33 줄
floor = 1;stops = 0;distance = 0;turns = 0;lastDir = 0; // 1이면 올라감, -1이면 내려감, 0이면 아직 움직이지 않음target = 콘솔.줄읽기().수로변환();// 끝 표시 0이 나오면 멈춘다: 0 뒤의 줄은 읽지 않는다동안 (target != 0){    만약 (target != floor)    {        gap = 수학.절댓값(target - floor);        만약 (floor > 0 != target > 0)        {            gap--; // 지상과 지하 사이에는 0층이 없다        }        d = -1;        만약 (target > floor)        {            d = 1;        }        만약 (lastDir != 0 && d != lastDir)        {            turns++;        }        stops++;        distance += gap;        lastDir = d;        floor = target;    }    target = 콘솔.줄읽기().수로변환();}콘솔.쓰기(stops + " " + distance + " " + turns);