{ }codelper
switch 语句嵌套条件P0242

电视遥控器按键

用遥控器操作一台有 1 到 c 号频道的电视。
一开始电视是关着的,频道是 1 号,音量是 10,静音关闭,没有上一个频道,也没有攒下的数字。
每个键是一个字符,按按下的顺序在一行中给出。
电视关着时,除了 P 和 ? 以外的键全部忽略。
关着时 P 打开电视,? 在一行中输出 OFF。
打开时,频道、音量、静音和上一个频道都与关机时相同。
开着时,数字键 0~9 把该数字接到攒下的数字末尾。
攒下的数字达到三位时立刻进行“数字处理”。
开着时,不是数字的键先进行“数字处理”,再做自己的事。
“数字处理”只在有攒下的数字时进行:把攒下的数字读成一个数(007 是 7)并清空。
若这个数在 1 到 c 之间,就转到那个频道。
超出范围就不转到任何频道。
开着时每个键做的事如下。
- #:什么也不做(只进行数字处理)。
- P:关闭电视。
- U:转到下一个频道。
c 号的下一个是 1 号。
- D:转到前一个编号的频道。
1 号的前一个是 c 号。
- B:转到上一个频道。
没有上一个频道时什么也不做。
- +:音量加 1(不超过 30),并取消静音。
- -:音量减 1(不低于 0),并取消静音。
- M:切换静音。
- ?:静音开着时输出 CH 频道 MUTE,否则输出 CH 频道 VOL 音量,占一行。
“转到”某个频道是指:只有当它与当前频道不同时,才把当前频道记为上一个频道,并把它设为当前频道。
与当前频道相同时什么都不变。
所有键按完后剩下的数字不处理。
第一行给出 c,第二行给出不含空格的按键。
每个 ? 输出一行。

输入
2 ≤ c ≤ 999。
按键有 1~10,000 个,每个是 0~9、#、P、U、D、B、+、-、M、?
之一。
至少有一个 ?
输出
与 ?
个数相同的行数
样例 1 · stdin
50
?P?37?U?BB?M?+?D5#?P?9P?
stdout
OFF
CH 1 VOL 10
CH 37 VOL 10
CH 38 VOL 10
CH 38 VOL 10
CH 38 MUTE
CH 38 VOL 11
CH 5 VOL 11
OFF
CH 5 VOL 11
样例 2 · stdin
3
PD?UU?B?000#?40#?+M?M?
stdout
CH 3 VOL 10
CH 2 VOL 10
CH 1 VOL 10
CH 1 VOL 10
CH 1 VOL 10
CH 1 MUTE
CH 1 VOL 11
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

这是用一个键选择分支的 switch。
按一个字符选择:C・C++・Java・C#・JS・TS switch (k) { case 'U': … }(JS・TS 用字符串 "U"),Python 3.10+ match k: case "U":,Craykon 选择 (k) { 情况 "U": … 跳出; }。
把做同样事情的情况合在一起(比如十个数字):C・C++・JS・TS・C#(仅限空 case)case '0': case '1': …,Java 箭头 case '+', '-' ->,Python case "+" | "-":,Craykon 情况 "0", "1", …:。
陷阱 ① 贯穿:C・C++・JS・TS 和 Java 旧式 case: 语句在缺少 break 时会接着执行下一个 case。
U 后面忘了 break 就会连 D 一起执行,频道又回到原处。
C# 把它当作编译错误,Java 箭头 switch、Python match、Craykon 选择 都不会贯穿。
Craykon 的 跳出 只跳出选择。
② 在 1 号按 D:(ch - 2) % c + 1 在 C・C++・Java・C#・JS・TS・Craykon 中因为 % 保留负号而得到 0 号。
要用 (ch - 2 + c) % c + 1 或 Java Math.floorMod(Python 的 % 总是不小于 0)。
③ 嵌套条件的顺序:要在 switch 之前先问“是否关着”,关机时音量和频道才不会变。
④ 所有非数字键都先处理攒下的数字(不只是 #)。
所以 5U 是 5 号的下一个 6 号。
⑤ 转到相同频道时不覆盖上一个频道。
⑥ +・- 会取消静音。

Pythonmain.py · 60 行
c = int(input())keys = input().strip() power = Falsech, vol, muted = 1, 10, Falseprev = 0      # 바로 전 채널(0이면 아직 없음)buf = ""      # 누른 숫자를 모아 둔 것out = []  def go(to):    """채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다."""    global ch, prev    if to != ch:        prev, ch = ch, to  def commit():    global buf    if buf:        v = int(buf)  # "007"은 7        buf = ""        if 1 <= v <= c:            go(v)  for k in keys:    if not power:        # 꺼져 있으면 P와 ? 말고는 듣지 않는다        if k == "P":            power = True        elif k == "?":            out.append("OFF")        continue    if k.isdigit():        buf += k        if len(buf) == 3:            commit()        continue    commit()  # 숫자가 아닌 키는 모아 둔 숫자부터 처리한다    match k:        case "#":            pass        case "P":            power = False        case "U":            go(ch % c + 1)        case "D":            go((ch - 2) % c + 1)  # Python의 %는 늘 0 이상이라 1번 → c번        case "B":            if prev:                go(prev)        case "+" | "-":            vol = min(30, vol + 1) if k == "+" else max(0, vol - 1)            muted = False        case "M":            muted = not muted        case "?":            out.append(f"CH {ch} MUTE" if muted else f"CH {ch} VOL {vol}")print("\n".join(out))
JavaScriptmain.js · 62 行
const [cLine, keysLine] = require("fs").readFileSync(0, "utf8").split("\n");const c = Number(cLine);const keys = keysLine.trim(); let power = false;let ch = 1, vol = 10, muted = false;let prev = 0; // 바로 전 채널(0이면 아직 없음)let buf = ""; // 누른 숫자를 모아 둔 것const out = []; const go = (to) => {  if (to !== ch) [prev, ch] = [ch, to]; // 지금과 같으면 바꾼 것이 아니다};const commit = () => {  if (buf === "") return;  const v = Number(buf); // "007"은 7  buf = "";  if (v >= 1 && v <= c) go(v);}; for (const k of keys) {  if (!power) {    // 꺼져 있으면 P와 ? 말고는 듣지 않는다    if (k === "P") power = true;    else if (k === "?") out.push("OFF");    continue;  }  if (k >= "0" && k <= "9") {    buf += k;    if (buf.length === 3) commit();    continue;  }  commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다  switch (k) {    case "#":      break;    case "P":      power = false;      break;    case "U":      go((ch % c) + 1);      break;    case "D":      go(((ch - 2 + c) % c) + 1); // JS의 %는 음수를 남기니 c를 더해 둔다      break;    case "B":      if (prev !== 0) go(prev);      break;    case "+":    case "-": // 두 경우가 같은 일을 하도록 일부러 이어 내려간다      vol = k === "+" ? Math.min(30, vol + 1) : Math.max(0, vol - 1);      muted = false;      break;    case "M":      muted = !muted;      break;    case "?":      out.push(muted ? `CH ${ch} MUTE` : `CH ${ch} VOL ${vol}`);      break;  }}console.log(out.join("\n"));
TypeScriptmain.ts · 64 行
import { readFileSync } from "node:fs"; const [cLine, keysLine]: string[] = readFileSync(0, "utf8").split("\n");const c = Number(cLine);const keys = keysLine.trim(); let power = false;let ch = 1, vol = 10, muted = false;let prev = 0; // 바로 전 채널(0이면 아직 없음)let buf = ""; // 누른 숫자를 모아 둔 것const out: string[] = []; const go = (to: number): void => {  if (to !== ch) [prev, ch] = [ch, to]; // 지금과 같으면 바꾼 것이 아니다};const commit = (): void => {  if (buf === "") return;  const v = Number(buf); // "007"은 7  buf = "";  if (v >= 1 && v <= c) go(v);}; for (const k of keys) {  if (!power) {    // 꺼져 있으면 P와 ? 말고는 듣지 않는다    if (k === "P") power = true;    else if (k === "?") out.push("OFF");    continue;  }  if (k >= "0" && k <= "9") {    buf += k;    if (buf.length === 3) commit();    continue;  }  commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다  switch (k) {    case "#":      break;    case "P":      power = false;      break;    case "U":      go((ch % c) + 1);      break;    case "D":      go(((ch - 2 + c) % c) + 1); // JS의 %는 음수를 남기니 c를 더해 둔다      break;    case "B":      if (prev !== 0) go(prev);      break;    case "+":    case "-": // 두 경우가 같은 일을 하도록 일부러 이어 내려간다      vol = k === "+" ? Math.min(30, vol + 1) : Math.max(0, vol - 1);      muted = false;      break;    case "M":      muted = !muted;      break;    case "?":      out.push(muted ? `CH ${ch} MUTE` : `CH ${ch} VOL ${vol}`);      break;  }}console.log(out.join("\n"));
JavaMain.java · 62 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException; public class Main {    static int c, ch = 1, vol = 10, prev = 0;    static boolean muted = false;    static StringBuilder buf = new StringBuilder(); // 누른 숫자를 모아 둔 것     // 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다    static void go(int to) {        if (to != ch) {            prev = ch;            ch = to;        }    }     static void commit() {        if (buf.length() == 0) return;        int v = Integer.parseInt(buf.toString()); // "007"은 7        buf.setLength(0);        if (v >= 1 && v <= c) go(v);    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        c = Integer.parseInt(in.readLine().trim());        String keys = in.readLine().trim();        boolean power = false;        StringBuilder out = new StringBuilder();        for (char k : keys.toCharArray()) {            if (!power) {                // 꺼져 있으면 P와 ? 말고는 듣지 않는다                if (k == 'P') power = true;                else if (k == '?') out.append("OFF\n");                continue;            }            if (Character.isDigit(k)) {                buf.append(k);                if (buf.length() == 3) commit();                continue;            }            commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다            // 화살표 switch는 이어 내려가지 않아 break가 필요 없다            switch (k) {                case '#' -> { }                case 'P' -> power = false;                case 'U' -> go(ch % c + 1);                case 'D' -> go(Math.floorMod(ch - 2, c) + 1); // floorMod는 늘 0 이상                case 'B' -> { if (prev != 0) go(prev); }                case '+', '-' -> {                    vol = k == '+' ? Math.min(30, vol + 1) : Math.max(0, vol - 1);                    muted = false;                }                case 'M' -> muted = !muted;                case '?' -> out.append("CH ").append(ch).append(muted ? " MUTE" : " VOL " + vol).append('\n');                default -> { }            }        }        System.out.print(out);    }}
C#Main.cs · 82 行
using System;using System.Text; class Program{    static int c, ch = 1, vol = 10, prev = 0;    static bool muted = false;    static string buf = ""; // 누른 숫자를 모아 둔 것     // 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다    static void Go(int to)    {        if (to != ch)        {            prev = ch;            ch = to;        }    }     static void Commit()    {        if (buf == "") return;        int v = int.Parse(buf); // "007"은 7        buf = "";        if (v >= 1 && v <= c) Go(v);    }     static void Main()    {        c = int.Parse(Console.ReadLine().Trim());        string keys = Console.ReadLine().Trim();        bool power = false;        var sb = new StringBuilder();        foreach (char k in keys)        {            if (!power)            {                // 꺼져 있으면 P와 ? 말고는 듣지 않는다                if (k == 'P') power = true;                else if (k == '?') sb.Append("OFF\n");                continue;            }            if (char.IsDigit(k))            {                buf += k;                if (buf.Length == 3) Commit();                continue;            }            Commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다            // C#은 case 끝에 break가 없으면 컴파일 오류라서 이어 내려가는 실수가 없다            switch (k)            {                case '#':                    break;                case 'P':                    power = false;                    break;                case 'U':                    Go(ch % c + 1);                    break;                case 'D':                    Go((ch - 2 + c) % c + 1); // C#의 %는 음수를 남기니 c를 더해 둔다                    break;                case 'B':                    if (prev != 0) Go(prev);                    break;                case '+':                case '-': // 빈 case는 다음 case와 묶을 수 있다                    vol = k == '+' ? Math.Min(30, vol + 1) : Math.Max(0, vol - 1);                    muted = false;                    break;                case 'M':                    muted = !muted;                    break;                case '?':                    sb.Append(muted ? $"CH {ch} MUTE\n" : $"CH {ch} VOL {vol}\n");                    break;            }        }        Console.Write(sb);    }}
C++main.cpp · 73 行
#include <algorithm>#include <iostream>#include <string> int c, ch = 1, vol = 10, prev = 0;bool muted = false;std::string buf; // 누른 숫자를 모아 둔 것 // 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다void go(int to) {    if (to != ch) {        prev = ch;        ch = to;    }} void commit() {    if (buf.empty()) return;    int v = std::stoi(buf); // "007"은 7    buf.clear();    if (v >= 1 && v <= c) go(v);} int main() {    std::string keys, out;    std::cin >> c >> keys;    bool power = false;    for (char k : keys) {        if (!power) {            // 꺼져 있으면 P와 ? 말고는 듣지 않는다            if (k == 'P') power = true;            else if (k == '?') out += "OFF\n";            continue;        }        if (k >= '0' && k <= '9') {            buf += k;            if (buf.size() == 3) commit();            continue;        }        commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다        switch (k) {        case '#':            break;        case 'P':            power = false;            break;        case 'U':            go(ch % c + 1);            break;        case 'D':            go((ch - 2 + c) % c + 1); // C++의 %는 음수를 남기니 c를 더해 둔다            break;        case 'B':            if (prev) go(prev);            break;        case '+':            vol = std::min(30, vol + 1);            muted = false;            break;        case '-':            vol = std::max(0, vol - 1);            muted = false;            break;        case 'M':            muted = !muted;            break;        case '?':            out += "CH " + std::to_string(ch) + (muted ? " MUTE" : " VOL " + std::to_string(vol)) + "\n";            break;        }    }    std::cout << out;}
Cmain.c · 81 行
#include <stdio.h>#include <stdlib.h> static int c, ch = 1, vol = 10, muted = 0, prev = 0;static char buf[4];static int blen = 0; /* 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다 */static void go(int to) {    if (to != ch) {        prev = ch;        ch = to;    }} static void commit(void) {    if (blen == 0) return;    buf[blen] = '\0';    int v = atoi(buf); /* "007"은 7 */    blen = 0;    if (v >= 1 && v <= c) go(v);} static char keys[10002]; int main(void) {    int power = 0;    scanf("%d %10001s", &c, keys);    for (char *p = keys; *p; p++) {        char k = *p;        if (!power) {            /* 꺼져 있으면 P와 ? 말고는 듣지 않는다 */            if (k == 'P') power = 1;            else if (k == '?') puts("OFF");            continue;        }        switch (k) {        /* 숫자 열 개는 case를 잇대어 써서 한 곳으로 모은다(일부러 이어 내려감) */        case '0': case '1': case '2': case '3': case '4':        case '5': case '6': case '7': case '8': case '9':            buf[blen++] = k;            if (blen == 3) commit();            continue; /* 아래의 commit을 건너뛰고 다음 키로 */        default:            break;        }        commit(); /* 숫자가 아닌 키는 모아 둔 숫자부터 처리한다 */        switch (k) {        case '#':            break;        case 'P':            power = 0;            break;        case 'U':            go(ch % c + 1);            break;        case 'D':            go((ch - 2 + c) % c + 1); /* C의 %는 음수를 남기니 c를 더해 둔다 */            break;        case 'B':            if (prev) go(prev);            break;        case '+':            vol = vol < 30 ? vol + 1 : 30;            muted = 0;            break;        case '-':            vol = vol > 0 ? vol - 1 : 0;            muted = 0;            break;        case 'M':            muted = !muted;            break;        case '?':            if (muted) printf("CH %d MUTE\n", ch);            else printf("CH %d VOL %d\n", ch, vol);            break;        }    }    return 0;}
Craykonmain.cray · 111 行
c = 控制台.读行().转数字();keys = 控制台.读行().去空白(); power = 假;ch = 1;vol = 10;muted = 假;prev = 0; // 바로 전 채널(0이면 아직 없음)buf = ""; // 누른 숫자를 모아 둔 것 // 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다가기(to){    如果 (to != ch)    {        prev = ch;        ch = to;    }} 모은숫자처리(){    如果 (buf != "")    {        v = buf.转数字(); // "007"은 7        buf = "";        如果 (v >= 1 && v <= c)        {            가기(v);        }    }} 循环 (i = 0; i < keys.长度; i++){    k = keys[i];    如果 (!power)    {        // 꺼져 있으면 P와 ? 말고는 듣지 않는다        如果 (k == "P")        {            power = 真;        }        否则 如果 (k == "?")        {            控制台.输出("OFF");        }        继续;    }    选择 (k)    {        情况 "0":        情况 "1":        情况 "2":        情况 "3":        情况 "4":        情况 "5":        情况 "6":        情况 "7":        情况 "8":        情况 "9":            buf = buf + k;            如果 (buf.长度 == 3)            {                모은숫자처리();            }            跳出;        默认:            모은숫자처리(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다            选择 (k)            {                情况 "P":                    power = 假;                    跳出;                情况 "U":                    가기(ch % c + 1);                    跳出;                情况 "D":                    가기((ch - 2 + c) % c + 1); // %는 음수를 남기니 c를 더해 둔다                    跳出;                情况 "B":                    如果 (prev != 0)                    {                        가기(prev);                    }                    跳出;                情况 "+":                    vol = 数学.较小值(30, vol + 1);                    muted = 假;                    跳出;                情况 "-":                    vol = 数学.较大值(0, vol - 1);                    muted = 假;                    跳出;                情况 "M":                    muted = !muted;                    跳出;                情况 "?":                    如果 (muted)                    {                        控制台.输出("CH " + ch + " MUTE");                    }                    否则                    {                        控制台.输出("CH " + ch + " VOL " + vol);                    }                    跳出;            }            跳出;    }}