{ }codelper
참·거짓그리고·또는P0324

수학여행 신청서 검사

수학여행 신청서 n장을 검사한다. 신청서 한 장은 학생 이름과, yes 또는 no로 답한 여덟 항목으로 이루어진다. 여덟 항목은 차례로 보호자 동의, 수영 신청, 건강 확인서 제출, 등산 신청, 공예 신청, 요리 신청, 도시락 지참, 급식 신청이다. 신청서는 다음 네 규칙을 모두 지켜야 한다. 규칙 1: 보호자 동의가 yes여야 한다. 규칙 2: 수영을 신청했으면 건강 확인서를 제출해야 한다(수영을 신청하지 않았으면 확인서는 내도 되고 내지 않아도 된다). 규칙 3: 등산, 공예, 요리 가운데 정확히 하나만 신청해야 한다. 규칙 4: 도시락 지참과 급식 신청 가운데 정확히 하나만 yes여야 한다. 신청서마다 주어진 차례대로 한 줄씩 출력한다. 네 규칙을 모두 지켰으면 이름 뒤에 빈칸 하나를 띄우고 ok를 출력한다. 그렇지 않으면 이름 뒤에 어긴 규칙의 번호를 모두, 작은 번호부터 빈칸 하나씩 띄워 출력한다. 마지막 줄에는 네 규칙을 모두 지킨 신청서의 수를 출력한다.

입력
첫 줄에 신청서 수 n이 주어진다.
다음 n줄에 이름과 여덟 항목의 답이 빈칸 하나씩 띄워 주어진다.
이름은 영어 소문자 1~10자이고(yes, no, ok일 수도 있고 서로 같을 수도 있다), 답은 yes 또는 no이다.
1 ≤ n ≤ 1,000
출력
n줄에 신청서마다 이름 ok 또는 이름 어긴 규칙 번호들을 출력하고, 마지막 줄에 통과한 신청서 수를 출력한다
예시 1 · stdin
4
mina yes yes yes no yes no yes no
jun no yes no yes yes yes yes yes
sora yes no no no no no no yes
dan yes no yes yes no no no yes
stdout
mina ok
jun 1 2 3 4
sora 3
dan ok
2
main.py
입력(stdin)

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

$ 준비됐어요

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

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

yes·no는 문자열이라, 먼저 참·거짓 값으로 바꿔 변수에 담고 규칙을 &&·||·!(Python은 and·or·not)로 써요.
바꾸는 식은 Python·C#·C++·크레이콘 tok == "yes", JS·TS tok === "yes", Java tok.equals("yes"), C strcmp(tok, "yes") == 0이에요.
자료형 이름은 Python·C#·C++ bool, JS·TS·Java boolean, C는 <stdbool.h>를 넣어야 bool을 쓸 수 있고, 크레이콘은 참·거짓이에요.
함정 여섯: ① 문자열을 바꾸지 않고 조건에 그대로 쓰는 일이에요.
Python·JavaScript·TypeScript·크레이콘에서는 빈 문자열만 거짓이라 "no"도 참으로 통하고, 오류도 나지 않아요.
Java·C#·C++(std::string)는 컴파일 오류로 막아 줘요.
② Java에서 tok == "yes"는 내용이 아니라 같은 객체인지를 물어서, 입력에서 읽은 yes에는 늘 거짓이에요.
③ C의 strcmp는 같을 때 0을 돌려줘요.
strcmp(tok, "yes")를 그대로 참·거짓으로 쓰면 yes와 no가 뒤집혀요.
④ '수영이면 확인서'는 swim && health가 아니에요.
그렇게 쓰면 수영을 신청하지 않은 sora가 규칙 2에 걸려요.
지킨 것은 !swim || health, 어긴 것은 swim && !health예요.
⑤ '셋 중 정확히 하나'를 hike ^ craft ^ cook으로 쓰면 셋 다 yes인 jun도 참이 돼요(참이 홀수 개면 참이라서요).
참의 개수를 세야 해요.
Python·JavaScript·C·C++는 참이 1, 거짓이 0으로 더해져서 hike + craft + cook == 1이라 쓸 수 있어요.
TypeScript·Java·C#·크레이콘은 참·거짓끼리 더하지 못하게 막아서(컴파일 오류, 크레이콘은 실행 중 오류) 만약 (a) { count += 1; }처럼 직접 세거나 C# Count(f => f)를 써요.
⑥ '둘 중 정확히 하나'는 packed || meal이 아니에요.
그러면 둘 다 yes인 jun이 규칙 4를 통과해요.
두 참·거짓이 서로 다른지 packed != meal로 물으면 돼요(JS·TS는 !==).

Pythonmain.py · 32 줄
import sys  def main():    lines = sys.stdin.read().split("\n")    n = int(lines[0])    out = []    passed = 0    for line in lines[1:n + 1]:        parts = line.split()        name = parts[0]        # "no"도 빈 문자열이 아니라서 참으로 통한다 → 꼭 "yes"와 견줘 참·거짓으로 바꾼다        consent, swim, health, hike, craft, cook, packed, meal = (tok == "yes" for tok in parts[1:9])        broken = []        if not consent:            broken.append(1)        if swim and not health:  # '수영이면 확인서'가 깨지는 경우는 이것 하나뿐이다            broken.append(2)        if hike + craft + cook != 1:  # 참은 1, 거짓은 0으로 더해진다            broken.append(3)        if packed == meal:  # 둘 중 정확히 하나 = 두 값이 서로 다르다            broken.append(4)        if broken:            out.append(name + " " + " ".join(map(str, broken)))        else:            out.append(name + " ok")            passed += 1    out.append(str(passed))    print("\n".join(out))  main()
JavaScriptmain.js · 23 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const out = [];let passed = 0;for (let i = 1; i <= n; i++) {  const parts = lines[i].trim().split(" ");  const name = parts[0];  // "no"도 빈 문자열이 아니라서 참으로 통한다 → 꼭 "yes"와 견줘 참·거짓으로 바꾼다  const [consent, swim, health, hike, craft, cook, packed, meal] = parts.slice(1, 9).map((tok) => tok === "yes");  const broken = [];  if (!consent) broken.push(1);  if (swim && !health) broken.push(2); // '수영이면 확인서'가 깨지는 경우는 이것 하나뿐이다  if (hike + craft + cook !== 1) broken.push(3); // 더하면 true는 1, false는 0이 된다  if (packed === meal) broken.push(4); // 둘 중 정확히 하나 = 두 값이 서로 다르다  if (broken.length > 0) {    out.push(name + " " + broken.join(" "));  } else {    out.push(name + " ok");    passed++;  }}out.push(passed);console.log(out.join("\n"));
TypeScriptmain.ts · 32 줄
import { readFileSync } from "node:fs"; // TypeScript는 boolean끼리 더하지 못하게 막는다 → 참인 것을 직접 센다function countTrue(...flags: boolean[]): number {  return flags.filter((f) => f).length;} const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);const out: string[] = [];let passed = 0;for (let i = 1; i <= n; i++) {  const parts: string[] = lines[i].trim().split(" ");  const name: string = parts[0];  // "no"도 빈 문자열이 아니라서 참으로 통한다 → 꼭 "yes"와 견줘 boolean으로 바꾼다  const [consent, swim, health, hike, craft, cook, packed, meal]: boolean[] = parts    .slice(1, 9)    .map((tok) => tok === "yes");  const broken: number[] = [];  if (!consent) broken.push(1);  if (swim && !health) broken.push(2); // '수영이면 확인서'가 깨지는 경우는 이것 하나뿐이다  if (countTrue(hike, craft, cook) !== 1) broken.push(3);  if (packed === meal) broken.push(4); // 둘 중 정확히 하나 = 두 값이 서로 다르다  if (broken.length > 0) {    out.push(name + " " + broken.join(" "));  } else {    out.push(name + " ok");    passed++;  }}out.push(String(passed));console.log(out.join("\n"));
JavaMain.java · 44 줄
import java.io.*;import java.util.*; public class Main {    // Java의 boolean은 수가 아니라서 더할 수 없다 → 1이나 0으로 바꿔 센다    static int countTrue(boolean... flags) {        int count = 0;        for (boolean f : flags) {            if (f) count++;        }        return count;    }     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        StringBuilder sb = new StringBuilder();        int passed = 0;        for (int i = 0; i < n; i++) {            StringTokenizer st = new StringTokenizer(br.readLine());            String name = st.nextToken();            boolean[] v = new boolean[8];            for (int j = 0; j < 8; j++) {                v[j] = st.nextToken().equals("yes"); // ==는 같은 객체인지를 묻는다. 내용은 equals로 견준다            }            boolean consent = v[0], swim = v[1], health = v[2];            boolean hike = v[3], craft = v[4], cook = v[5];            boolean packed = v[6], meal = v[7];            StringBuilder broken = new StringBuilder();            if (!consent) broken.append(" 1");            if (swim && !health) broken.append(" 2"); // '수영이면 확인서'가 깨지는 경우는 이것 하나뿐이다            if (countTrue(hike, craft, cook) != 1) broken.append(" 3");            if (packed == meal) broken.append(" 4"); // 둘 중 정확히 하나 = 두 값이 서로 다르다            if (broken.length() > 0) {                sb.append(name).append(broken).append('\n');            } else {                sb.append(name).append(" ok\n");                passed++;            }        }        sb.append(passed).append('\n');        System.out.print(sb);    }}
C#Main.cs · 41 줄
using System;using System.Collections.Generic;using System.Linq;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine()!.Trim());        var sb = new StringBuilder();        int passed = 0;        for (int i = 0; i < n; i++)        {            string[] parts = Console.ReadLine()!.Split(' ', StringSplitOptions.RemoveEmptyEntries);            string name = parts[0];            // C#의 ==는 문자열의 내용을 견준다            bool[] v = parts.Skip(1).Take(8).Select(tok => tok == "yes").ToArray();            bool consent = v[0], swim = v[1], health = v[2];            bool hike = v[3], craft = v[4], cook = v[5];            bool packed = v[6], meal = v[7];            var broken = new List<int>();            if (!consent) broken.Add(1);            if (swim && !health) broken.Add(2); // '수영이면 확인서'가 깨지는 경우는 이것 하나뿐이다            // bool은 수가 아니라서 더할 수 없다 → 참인 것을 센다            if (new[] { hike, craft, cook }.Count(f => f) != 1) broken.Add(3);            if (packed == meal) broken.Add(4); // 둘 중 정확히 하나 = 두 값이 서로 다르다            if (broken.Count > 0)            {                sb.Append(name).Append(' ').Append(string.Join(" ", broken)).Append('\n');            }            else            {                sb.Append(name).Append(" ok\n");                passed++;            }        }        sb.Append(passed).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 38 줄
#include <iostream>#include <string> int main() {    std::ios::sync_with_stdio(false);    int n;    std::cin >> n;    int passed = 0;    for (int i = 0; i < n; i++) {        std::string name;        std::cin >> name;        bool v[8];        for (int j = 0; j < 8; j++) {            std::string tok;            std::cin >> tok;            v[j] = tok == "yes"; // std::string의 ==는 내용을 견준다        }        bool consent = v[0], swim = v[1], health = v[2];        bool hike = v[3], craft = v[4], cook = v[5];        bool packed = v[6], meal = v[7];        bool r1 = consent;        bool r2 = !swim || health; // 수영을 하지 않으면 확인서는 묻지 않는다        bool r3 = hike + craft + cook == 1; // bool은 1 아니면 0이라 더해서 셀 수 있다        bool r4 = packed != meal;           // 둘 중 정확히 하나 = 두 값이 서로 다르다        if (r1 && r2 && r3 && r4) {            std::cout << name << " ok\n";            passed++;        } else {            std::cout << name;            if (!r1) std::cout << " 1";            if (!r2) std::cout << " 2";            if (!r3) std::cout << " 3";            if (!r4) std::cout << " 4";            std::cout << '\n';        }    }    std::cout << passed << '\n';}
Cmain.c · 39 줄
#include <stdbool.h>#include <stdio.h>#include <string.h> int main(void) {    int n;    if (scanf("%d", &n) != 1) return 1;    int passed = 0;    for (int i = 0; i < n; i++) {        char name[11];        bool v[8];        if (scanf("%10s", name) != 1) return 1;        for (int j = 0; j < 8; j++) {            char tok[4];            if (scanf("%3s", tok) != 1) return 1;            v[j] = strcmp(tok, "yes") == 0; // strcmp는 같을 때 0을 돌려준다        }        bool consent = v[0], swim = v[1], health = v[2];        bool hike = v[3], craft = v[4], cook = v[5];        bool packed = v[6], meal = v[7];        bool r1 = consent;        bool r2 = !swim || health; // 수영을 하지 않으면 확인서는 묻지 않는다        bool r3 = hike + craft + cook == 1; // bool은 1 아니면 0이라 더해서 셀 수 있다        bool r4 = packed != meal;           // 둘 중 정확히 하나 = 두 값이 서로 다르다        if (r1 && r2 && r3 && r4) {            printf("%s ok\n", name);            passed++;        } else {            printf("%s", name);            if (!r1) printf(" 1");            if (!r2) printf(" 2");            if (!r3) printf(" 3");            if (!r4) printf(" 4");            printf("\n");        }    }    printf("%d\n", passed);    return 0;}
Craykonmain.cray · 62 줄
// 참·거짓은 수가 아니라서 더할 수 없다 → 참인 것을 직접 센다참개수(a, b, c){    count = 0;    만약 (a)    {        count += 1;    }    만약 (b)    {        count += 1;    }    만약 (c)    {        count += 1;    }    돌려주기 count;} n = 콘솔.줄읽기().수로변환();passed = 0;반복 (i = 0; i < n; i++){    parts = 콘솔.줄읽기().나누기();    name = parts[0];    // 문자열을 "yes"와 견줘 참·거짓으로 바꾼다    consent = parts[1] == "yes";    swim = parts[2] == "yes";    health = parts[3] == "yes";    hike = parts[4] == "yes";    craft = parts[5] == "yes";    cook = parts[6] == "yes";    packed = parts[7] == "yes";    meal = parts[8] == "yes";    broken = "";    만약 (!consent)    {        broken += " 1";    }    만약 (swim && !health)    {        broken += " 2"; // '수영이면 확인서'가 깨지는 경우는 이것 하나뿐이다    }    만약 (참개수(hike, craft, cook) != 1)    {        broken += " 3";    }    만약 (packed == meal)    {        broken += " 4"; // 둘 중 정확히 하나 = 두 값이 서로 다르다    }    만약 (broken == "")    {        콘솔.쓰기(name + " ok");        passed += 1;    }    아니면    {        콘솔.쓰기(name + broken);    }}콘솔.쓰기(passed);