{ }codelper
真偽値P0289

一度鳴ったら切るまで鳴り続けるサイレン

警報器の記録が n 行ある。
記録一行には、その瞬間の三つの状態が順に書かれている:警報器が入っているか、ドアが開いているか、窓が開いているか。
各状態は小文字の true または false である。
サイレンははじめ止まっていて、記録を一行読むたびに次の規則で決まる。
警報器が切れていれば(false)、サイレンは止まる。
警報器が入っていれば(true)、直前の記録までサイレンが鳴っていたか、いまドアと窓のうち少なくとも一つが開いているときにサイレンが鳴る。
警報器が入っていても、その二つのどちらでもなければサイレンは止まっている。
つまり、一度鳴り始めたサイレンは、ドアと窓を両方閉めても警報器を切るまで鳴り続ける。
記録ごとに、その記録を読んだあとサイレンが鳴っていれば true、そうでなければ false を一行に出力せよ。
最後の行には、サイレンが止まっている状態から鳴り始めた回数を出力せよ。

入力
一行目に n(1 ≤ n ≤ 1,000)、続く n 行に true または false が三つずつ空白一つで区切って与えられる。
出力
n + 1 行。
はじめの n 行は小文字の true または false、最後の行はサイレンが鳴り始めた回数(一度もなければ 0)
例 1 · stdin
7
false true false
true false false
true false true
true false false
false false false
true true true
true false false
stdout
false
false
true
true
false
true
true
2
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

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

ほかの言語では?言語別の解答を見る · 8 言語の解答

真偽値一つ(サイレン)を行ごとに armed && (siren || door || window) で決め直す問題です。
八つの言語すべてで &&(Python は and)が ||(or)より先に結びつきます。
違うのは、単語 "true" を真偽値に変える方法と、もう一度出力する方法です。
読み込み:Java は Boolean.parseBoolean(単語)、C# は bool.Parse(単語)、C++ は std::cin >> std::boolalpha を入れておけば bool にそのまま読めます。
Python・JavaScript・TypeScript・C・Craykon は 単語 == "true" のように比較して作ります(C は strcmp(単語, "true") == 0、bool を使うには <stdbool.h>)。
出力:Java と JS・TS はそのまま出すと true/false、Python と C# は True/False、C++ は std::boolalpha なしだと 1/0 で、C の printf には bool の書式がありません。
Craykon の真偽値は 真・偽 と書き、ここでは サイレン ? "true" : "false" で単語を選んで出力します。
落とし穴は五つ:① Python の bool("false") と JS の Boolean("false") は真です。
空でない文字列はすべて真なので、変換ではなく比較をします。
② かっこを外して armed && siren || door || window と書くと (armed && siren) || door || window になり、警報器を切っていてもドアが開くと鳴ります。
③ 式に前の行のサイレンの値を入れないと、ドアを閉めた瞬間にサイレンが止まります。
④ 出力は小文字でなければなりません。
C# で bool をそのままつなぐと True、C++ で std::boolalpha なしに出すと 1 です。
⑤ 回数はサイレンが鳴っている行の数ではなく、「前は止まっていて今は鳴っている」行の数です。
新しい値を入れる前に、前の値を別の変数に取っておきます。

Pythonmain.py · 12 行
n = int(input())siren = Falsecount = 0for _ in range(n):    # bool("false")는 True다(빈 문자열만 False). 그래서 "true"와 같은지 비교해서 bool을 만든다    armed, door, window = (word == "true" for word in input().split())    was = siren    siren = armed and (siren or door or window)    if siren and not was:        count += 1    print("true" if siren else "false")  # print(siren)은 True/False로 찍힌다print(count)
JavaScriptmain.js · 15 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);let siren = false;let count = 0;const out = [];for (let i = 1; i <= n; i++) {  // Boolean("false")는 true다(빈 문자열만 false). 그래서 "true"와 같은지 비교한다  const [armed, door, windowOpen] = lines[i].split(" ").map((word) => word === "true");  const was = siren;  siren = armed && (siren || door || windowOpen);  if (siren && !was) count++;  out.push(String(siren)); // "true" 또는 "false"}out.push(count);console.log(out.join("\n"));
TypeScriptmain.ts · 19 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);let siren = false;let count = 0;const out: string[] = [];for (let i = 1; i <= n; i++) {  // Boolean("false")는 true다(빈 문자열만 false). 그래서 "true"와 같은지 비교한다  const flags: boolean[] = lines[i].split(" ").map((word) => word === "true");  const armed = flags[0];  const door = flags[1];  const windowOpen = flags[2];  const was = siren;  siren = armed && (siren || door || windowOpen);  if (siren && !was) count++;  out.push(String(siren)); // "true" 또는 "false"}out.push(String(count));console.log(out.join("\n"));
JavaMain.java · 25 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(in.readLine().trim());        boolean siren = false;        int count = 0;        StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            String[] words = in.readLine().trim().split(" ");            boolean armed = Boolean.parseBoolean(words[0]);            boolean door = Boolean.parseBoolean(words[1]);            boolean window = Boolean.parseBoolean(words[2]);            boolean was = siren;            siren = armed && (siren || door || window);            if (siren && !was) count++;            out.append(siren).append('\n'); // boolean은 true/false로 붙는다        }        out.append(count).append('\n');        System.out.print(out);    }}
C#Main.cs · 27 行
using System;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine());        bool siren = false;        int count = 0;        var sb = new StringBuilder();        for (int i = 0; i < n; i++)        {            string[] words = Console.ReadLine().Split(' ');            bool armed = bool.Parse(words[0]);            bool door = bool.Parse(words[1]);            bool window = bool.Parse(words[2]);            bool was = siren;            siren = armed && (siren || door || window);            if (siren && !was) count++;            // bool을 그대로 붙이면 True/False(첫 글자가 대문자)가 되므로 직접 고른다            sb.Append(siren ? "true" : "false").Append('\n');        }        sb.Append(count).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 20 行
#include <iostream> int main() {    int n;    std::cin >> n;    // boolalpha를 켜면 bool을 1/0이 아니라 true/false라는 낱말로 읽고 쓴다    std::cin >> std::boolalpha;    std::cout << std::boolalpha;    bool siren = false;    int count = 0;    for (int i = 0; i < n; i++) {        bool armed, door, window;        std::cin >> armed >> door >> window;        bool was = siren;        siren = armed && (siren || door || window);        if (siren && !was) count++;        std::cout << siren << '\n';    }    std::cout << count << '\n';}
Cmain.c · 30 行
#include <stdbool.h>#include <stdio.h>#include <string.h> /* 낱말 하나를 읽어 "true"인지 돌려준다 */static bool read_flag(void) {    char word[8];    scanf("%7s", word);    return strcmp(word, "true") == 0;} int main(void) {    int n;    scanf("%d", &n);    bool siren = false;    int count = 0;    for (int i = 0; i < n; i++) {        bool armed = read_flag();        bool door = read_flag();        bool window = read_flag();        bool was = siren;        /* &&가 ||보다 먼저 묶이므로 괄호가 꼭 있어야 한다 */        siren = armed && (siren || door || window);        if (siren && !was) count++;        /* printf에는 bool을 찍는 서식이 없다(%d로 찍으면 1/0) */        puts(siren ? "true" : "false");    }    printf("%d\n", count);    return 0;}
Craykonmain.cray · 19 行
n = コンソール.行読み().数に();경보 = 偽;횟수 = 0;繰り返す (i = 0; i < n; i++){    낱말 = コンソール.行読み().分ける(" ");    // 문자열 "false"는 거짓이 아니다. "true"와 같은지 비교해서 참·거짓을 만든다    켜짐 = 낱말[0] == "true";    문 = 낱말[1] == "true";    창문 = 낱말[2] == "true";    전 = 경보;    경보 = 켜짐 && (경보 || 문 || 창문);    もし (경보 && !전)    {        횟수++;    }    コンソール.書く(경보 ? "true" : "false");}コンソール.書く(횟수);