{ }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()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

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

ほかの言語では?言語別の解答を見る · 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 します。
Craykon はループの前で一回読み、間 (x != 0) の中のいちばん最後でまた読みます。
do { 読んで処理 } while (x != 0) のように処理を先にすると、終わりの印 0 まで階として扱い、エレベーターがない 0 階へ行ってしまいます。
入力の終わりまで読みながら 0 だけを飛ばすのも間違いです。
0 の後に残った行まで処理してしまいます。
Craykon コンソール.行読み() は文字列 "0" を返し、"0" と数の 0 は等しくないので、数に() をせずに 0 と比べると印を通り過ぎて入力の終わりの なし で止まります。
同じ階の要求は、Python・JS・TS・Java・C#・C・C++ では continue で飛ばせば済みます。
読むことがループの条件の中かループの先頭にあるので、次の行が読まれるからです。
Craykon のように、また読む行がループのいちばん最後にあると、次へ がその行まで飛ばしてしまい、同じ値で回り続け、「時間がかかりすぎます」のエラーで止まります。
そこで Craykon の解答は もし (target != floor) の中に処理を入れ、また読む行はそのブロックの外に置きます。
距離は Python abs、JS・TS・Java Math.abs、C# Math.Abs、C abs(<stdlib.h>)、C++ std::abs(<cstdlib>)、Craykon 数学.絶対値 で求め、二つの階の符号が違えば(一方が地上、一方が地下)ない 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);