{ }codelper
哨兵循环嵌套条件P0139

跟踪 ATM 的状态

模拟一台只用一张卡的取款机。
第一行给出账户余额 B、四位密码 P 和机器里的现金 M,之间各隔一个空格。
P 可能以 0 开头(例如 0123)。
从第二行起每行给出一条命令,出现 quit 命令时结束。
quit 后面即使还有行也不处理。
机器的状态是 idle(没有卡)、card(卡已插入但还没输对密码)、ready(密码已输对)三者之一,开始时是 idle。
机器会记住密码输错的次数。
这个次数在拔卡后再插入时也会延续,输对密码时变为 0。
每条命令按下面的方式处理并输出一行。
insert:如果卡曾被吞掉,输出 "已停用"。
否则如果状态不是 idle,输出 "无效操作"。
其余情况把状态改为 card,输出 "已插卡"。
pin x:如果状态不是 card,输出 "无效操作"(不计入输错次数)。
如果 x 与 P 的文字完全相同,就把状态改为 ready、输错次数改为 0,输出 "确认"。
不同则输错次数加 1。
次数达到 3 时机器吞卡,把状态改为 idle,输出 "吞卡";否则输出 "错误"。
withdraw n:如果状态不是 ready,输出 "无效操作"。
如果 n 大于余额,输出 "余额不足"。
否则如果 n 大于机器里的现金,输出 "现金不足"。
其余情况从余额和机器现金中各减去 n,输出新的余额。
deposit n:如果状态不是 ready,输出 "无效操作"。
否则给余额和机器现金各加上 n,输出新的余额。
balance:如果状态不是 ready,输出 "无效操作",否则输出余额。
eject:如果状态是 idle,输出 "无效操作"。
其余情况把状态改为 idle,输出 "已退卡"。
遇到 quit 时,在最后一行输出余额和机器现金,中间隔一个空格。

输入
0 ≤ B ≤ 10^9,0 ≤ M ≤ 10^9,P 是四位数字,到 quit 为止的命令为 1~1,000 行(含 quit),quit 一定会出现,pin 的 x 是 1~6 位数字,1 ≤ n ≤ 10^6
输出
quit 之前的每条命令一行,最后一行是余额和现金
样例 1 · stdin
100000 4821 50000
insert
pin 4821
withdraw 30000
withdraw 80000
withdraw 30000
deposit 15000
withdraw 30000
balance
eject
withdraw 1000
quit
insert
stdout
已插卡
确认
70000
余额不足
现金不足
85000
55000
55000
已退卡
无效操作
55000 5000
样例 2 · stdin
50000 0123 30000
balance
insert
pin 123
pin 1230
eject
insert
pin 0000
insert
quit
stdout
无效操作
已插卡
错误
错误
已退卡
已插卡
吞卡
已停用
50000 30000
main.py
输入(stdin)

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

$ 就绪

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

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

这是读到结束标记 quit 为止的循环:先读一行,然后 while (cmd != "quit") { 处理; 读下一行 }。
如果一直读到输入结束(EOF),就会连 quit 后面的行(第一个例子最后的 insert)也处理,答案就变了。
先按命令分支,再在里面询问状态和数值,这是嵌套条件。
内层条件的顺序就是规则,所以在 withdraw 里先问现金不足、后问余额不足的话,两者都不够时答案会变。
密码要按字符串比较。
转成数字会让 0123 和 123 相等,第二个例子里的 pin 123 就会被当成正确。
字符串相等在 Python、C#、JS、TS、C++(std::string)用 ==,Java 用 equals(== 比较是否同一个对象),C 用 strcmp(a, b) == 0。
C 里的 a == b 比较的是数组地址,永远为假。
状态名在 C 可以用 enum { IDLE, CARD, READY },C++ 用 enum class,其他语言可以用字符串常量。
Craykon 用 当 (p[0] != "quit") 循环,分支用 如果 … 否则 如果 … 否则。
每次插卡都把输错次数清零也是常见错误(第二个例子里重新插卡后只要再错一次就会吞卡)。

Pythonmain.py · 69 行
import sys first = sys.stdin.readline().split()balance, pin, cash = int(first[0]), first[1], int(first[2])  # PIN은 0으로 시작할 수 있어 문자열로 둔다state = "idle"      # idle(카드 없음) → card(카드 들어옴) → ready(PIN 확인됨)wrong = 0           # 틀린 횟수: 카드를 뺐다 넣어도 이어진다retained = False    # 세 번 틀려 기계가 카드를 가져갔나out = [] line = sys.stdin.readline().split()while line[0] != "quit":  # quit이 끝 표시: 그 뒤의 줄은 읽지 않는다    cmd = line[0]    if cmd == "insert":        if retained:            out.append("已停用")        elif state != "idle":            out.append("无效操作")        else:            state = "card"            out.append("已插卡")    elif cmd == "pin":        if state != "card":            out.append("无效操作")        elif line[1] == pin:            state = "ready"            wrong = 0            out.append("确认")        else:            wrong += 1            if wrong == 3:                retained = True                state = "idle"                out.append("吞卡")            else:                out.append("错误")    elif cmd == "withdraw":        n = int(line[1])        if state != "ready":            out.append("无效操作")        elif n > balance:            out.append("余额不足")        elif n > cash:            out.append("现金不足")        else:            balance -= n            cash -= n            out.append(str(balance))    elif cmd == "deposit":        if state != "ready":            out.append("无效操作")        else:            n = int(line[1])            balance += n            cash += n            out.append(str(balance))    elif cmd == "balance":        if state != "ready":            out.append("无效操作")        else:            out.append(str(balance))    else:  # eject        if state == "idle":            out.append("无效操作")        else:            state = "idle"            out.append("已退卡")    line = sys.stdin.readline().split()out.append(f"{balance} {cash}")print("\n".join(out))
JavaScriptmain.js · 69 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const first = lines[0].trim().split(/\s+/);let balance = Number(first[0]);const pin = first[1]; // PIN은 0으로 시작할 수 있어 문자열로 둔다let cash = Number(first[2]);let state = "idle"; // idle(카드 없음) → card(카드 들어옴) → ready(PIN 확인됨)let wrong = 0; // 틀린 횟수: 카드를 뺐다 넣어도 이어진다let retained = false; // 세 번 틀려 기계가 카드를 가져갔나const out = []; let i = 1;let p = lines[i].trim().split(/\s+/);while (p[0] !== "quit") { // quit이 끝 표시: 그 뒤의 줄은 읽지 않는다  const cmd = p[0];  if (cmd === "insert") {    if (retained) out.push("已停用");    else if (state !== "idle") out.push("无效操作");    else {      state = "card";      out.push("已插卡");    }  } else if (cmd === "pin") {    if (state !== "card") out.push("无效操作");    else if (p[1] === pin) {      state = "ready";      wrong = 0;      out.push("确认");    } else {      wrong++;      if (wrong === 3) {        retained = true;        state = "idle";        out.push("吞卡");      } else {        out.push("错误");      }    }  } else if (cmd === "withdraw") {    const n = Number(p[1]);    if (state !== "ready") out.push("无效操作");    else if (n > balance) out.push("余额不足");    else if (n > cash) out.push("现金不足");    else {      balance -= n;      cash -= n;      out.push(String(balance));    }  } else if (cmd === "deposit") {    if (state !== "ready") out.push("无效操作");    else {      const n = Number(p[1]);      balance += n;      cash += n;      out.push(String(balance));    }  } else if (cmd === "balance") {    out.push(state !== "ready" ? "无效操作" : String(balance));  } else { // eject    if (state === "idle") out.push("无效操作");    else {      state = "idle";      out.push("已退卡");    }  }  i++;  p = lines[i].trim().split(/\s+/);}out.push(`${balance} ${cash}`);console.log(out.join("\n"));
TypeScriptmain.ts · 70 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const first: string[] = lines[0].trim().split(/\s+/);let balance: number = Number(first[0]);const pin: string = first[1]; // PIN은 0으로 시작할 수 있어 문자열로 둔다let cash: number = Number(first[2]);let state: string = "idle"; // idle(카드 없음) → card(카드 들어옴) → ready(PIN 확인됨)let wrong = 0; // 틀린 횟수: 카드를 뺐다 넣어도 이어진다let retained = false; // 세 번 틀려 기계가 카드를 가져갔나const out: string[] = []; let i = 1;let p: string[] = lines[i].trim().split(/\s+/);while (p[0] !== "quit") { // quit이 끝 표시: 그 뒤의 줄은 읽지 않는다  const cmd = p[0];  if (cmd === "insert") {    if (retained) out.push("已停用");    else if (state !== "idle") out.push("无效操作");    else {      state = "card";      out.push("已插卡");    }  } else if (cmd === "pin") {    if (state !== "card") out.push("无效操作");    else if (p[1] === pin) {      state = "ready";      wrong = 0;      out.push("确认");    } else {      wrong++;      if (wrong === 3) {        retained = true;        state = "idle";        out.push("吞卡");      } else {        out.push("错误");      }    }  } else if (cmd === "withdraw") {    const n: number = Number(p[1]);    if (state !== "ready") out.push("无效操作");    else if (n > balance) out.push("余额不足");    else if (n > cash) out.push("现金不足");    else {      balance -= n;      cash -= n;      out.push(String(balance));    }  } else if (cmd === "deposit") {    if (state !== "ready") out.push("无效操作");    else {      const n: number = Number(p[1]);      balance += n;      cash += n;      out.push(String(balance));    }  } else if (cmd === "balance") {    out.push(state !== "ready" ? "无效操作" : String(balance));  } else { // eject    if (state === "idle") out.push("无效操作");    else {      state = "idle";      out.push("已退卡");    }  }  i++;  p = lines[i].trim().split(/\s+/);}out.push(`${balance} ${cash}`);console.log(out.join("\n"));
JavaMain.java · 76 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        String[] first = br.readLine().trim().split("\\s+");        int balance = Integer.parseInt(first[0]);        String pin = first[1]; // PIN은 0으로 시작할 수 있어 문자열로 둔다        int cash = Integer.parseInt(first[2]);        String state = "idle"; // idle(카드 없음) → card(카드 들어옴) → ready(PIN 확인됨)        int wrong = 0; // 틀린 횟수: 카드를 뺐다 넣어도 이어진다        boolean retained = false; // 세 번 틀려 기계가 카드를 가져갔나        StringBuilder out = new StringBuilder();         String[] p = br.readLine().trim().split("\\s+");        while (!p[0].equals("quit")) { // quit이 끝 표시: 그 뒤의 줄은 읽지 않는다            String cmd = p[0];            if (cmd.equals("insert")) {                if (retained) out.append("已停用\n");                else if (!state.equals("idle")) out.append("无效操作\n");                else {                    state = "card";                    out.append("已插卡\n");                }            } else if (cmd.equals("pin")) {                if (!state.equals("card")) out.append("无效操作\n");                else if (p[1].equals(pin)) {                    state = "ready";                    wrong = 0;                    out.append("确认\n");                } else {                    wrong++;                    if (wrong == 3) {                        retained = true;                        state = "idle";                        out.append("吞卡\n");                    } else {                        out.append("错误\n");                    }                }            } else if (cmd.equals("withdraw")) {                int n = Integer.parseInt(p[1]);                if (!state.equals("ready")) out.append("无效操作\n");                else if (n > balance) out.append("余额不足\n");                else if (n > cash) out.append("现金不足\n");                else {                    balance -= n;                    cash -= n;                    out.append(balance).append('\n');                }            } else if (cmd.equals("deposit")) {                if (!state.equals("ready")) out.append("无效操作\n");                else {                    int n = Integer.parseInt(p[1]);                    balance += n;                    cash += n;                    out.append(balance).append('\n');                }            } else if (cmd.equals("balance")) {                if (!state.equals("ready")) out.append("无效操作\n");                else out.append(balance).append('\n');            } else { // eject                if (state.equals("idle")) out.append("无效操作\n");                else {                    state = "idle";                    out.append("已退卡\n");                }            }            p = br.readLine().trim().split("\\s+");        }        out.append(balance).append(' ').append(cash).append('\n');        System.out.print(out);    }}
C#Main.cs · 98 行
using System;using System.Text; class Program{    static void Main()    {        string[] first = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int balance = int.Parse(first[0]);        string pin = first[1]; // PIN은 0으로 시작할 수 있어 문자열로 둔다        int cash = int.Parse(first[2]);        string state = "idle"; // idle(카드 없음) → card(카드 들어옴) → ready(PIN 확인됨)        int wrong = 0; // 틀린 횟수: 카드를 뺐다 넣어도 이어진다        bool retained = false; // 세 번 틀려 기계가 카드를 가져갔나        var sb = new StringBuilder();         string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        while (p[0] != "quit") // quit이 끝 표시: 그 뒤의 줄은 읽지 않는다        {            string cmd = p[0];            if (cmd == "insert")            {                if (retained) sb.Append("已停用\n");                else if (state != "idle") sb.Append("无效操作\n");                else                {                    state = "card";                    sb.Append("已插卡\n");                }            }            else if (cmd == "pin")            {                if (state != "card") sb.Append("无效操作\n");                else if (p[1] == pin)                {                    state = "ready";                    wrong = 0;                    sb.Append("确认\n");                }                else                {                    wrong++;                    if (wrong == 3)                    {                        retained = true;                        state = "idle";                        sb.Append("吞卡\n");                    }                    else                    {                        sb.Append("错误\n");                    }                }            }            else if (cmd == "withdraw")            {                int n = int.Parse(p[1]);                if (state != "ready") sb.Append("无效操作\n");                else if (n > balance) sb.Append("余额不足\n");                else if (n > cash) sb.Append("现金不足\n");                else                {                    balance -= n;                    cash -= n;                    sb.Append(balance).Append('\n');                }            }            else if (cmd == "deposit")            {                if (state != "ready") sb.Append("无效操作\n");                else                {                    int n = int.Parse(p[1]);                    balance += n;                    cash += n;                    sb.Append(balance).Append('\n');                }            }            else if (cmd == "balance")            {                if (state != "ready") sb.Append("无效操作\n");                else sb.Append(balance).Append('\n');            }            else // eject            {                if (state == "idle") sb.Append("无效操作\n");                else                {                    state = "idle";                    sb.Append("已退卡\n");                }            }            p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        }        sb.Append(balance).Append(' ').Append(cash).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 78 行
#include <iostream>#include <sstream>#include <string> enum class State { Idle, Card, Ready }; // 카드 없음 → 카드 들어옴 → PIN 확인됨 int main() {    int balance, cash;    std::string pin; // PIN은 0으로 시작할 수 있어 문자열로 둔다    std::cin >> balance >> pin >> cash;    State state = State::Idle;    int wrong = 0;         // 틀린 횟수: 카드를 뺐다 넣어도 이어진다    bool retained = false; // 세 번 틀려 기계가 카드를 가져갔나    std::ostringstream out;     std::string cmd;    std::cin >> cmd;    while (cmd != "quit") { // quit이 끝 표시: 그 뒤의 줄은 읽지 않는다        if (cmd == "insert") {            if (retained) out << "已停用\n";            else if (state != State::Idle) out << "无效操作\n";            else {                state = State::Card;                out << "已插卡\n";            }        } else if (cmd == "pin") {            std::string guess;            std::cin >> guess;            if (state != State::Card) out << "无效操作\n";            else if (guess == pin) {                state = State::Ready;                wrong = 0;                out << "确认\n";            } else {                wrong++;                if (wrong == 3) {                    retained = true;                    state = State::Idle;                    out << "吞卡\n";                } else {                    out << "错误\n";                }            }        } else if (cmd == "withdraw") {            int n;            std::cin >> n;            if (state != State::Ready) out << "无效操作\n";            else if (n > balance) out << "余额不足\n";            else if (n > cash) out << "现金不足\n";            else {                balance -= n;                cash -= n;                out << balance << '\n';            }        } else if (cmd == "deposit") {            int n;            std::cin >> n;            if (state != State::Ready) out << "无效操作\n";            else {                balance += n;                cash += n;                out << balance << '\n';            }        } else if (cmd == "balance") {            if (state != State::Ready) out << "无效操作\n";            else out << balance << '\n';        } else { // eject            if (state == State::Idle) out << "无效操作\n";            else {                state = State::Idle;                out << "已退卡\n";            }        }        std::cin >> cmd;    }    out << balance << ' ' << cash << '\n';    std::cout << out.str();}
Cmain.c · 76 行
#include <stdbool.h>#include <stdio.h>#include <stdlib.h>#include <string.h> enum { IDLE, CARD, READY }; /* 카드 없음 → 카드 들어옴 → PIN 확인됨 */ int main(void) {    int balance, cash;    char pin[8]; /* PIN은 0으로 시작할 수 있어 문자열로 둔다 */    char line[64], cmd[16], arg[16];    if (!fgets(line, sizeof line, stdin)) return 0;    sscanf(line, "%d %7s %d", &balance, pin, &cash);    int state = IDLE;    int wrong = 0;          /* 틀린 횟수: 카드를 뺐다 넣어도 이어진다 */    bool retained = false;  /* 세 번 틀려 기계가 카드를 가져갔나 */     while (fgets(line, sizeof line, stdin)) {        arg[0] = '\0';        sscanf(line, "%15s %15s", cmd, arg);        if (strcmp(cmd, "quit") == 0) break; /* quit이 끝 표시: 그 뒤의 줄은 읽지 않는다 */        if (strcmp(cmd, "insert") == 0) {            if (retained) puts("已停用");            else if (state != IDLE) puts("无效操作");            else {                state = CARD;                puts("已插卡");            }        } else if (strcmp(cmd, "pin") == 0) {            if (state != CARD) puts("无效操作");            else if (strcmp(arg, pin) == 0) {                state = READY;                wrong = 0;                puts("确认");            } else {                wrong++;                if (wrong == 3) {                    retained = true;                    state = IDLE;                    puts("吞卡");                } else {                    puts("错误");                }            }        } else if (strcmp(cmd, "withdraw") == 0) {            int n = atoi(arg);            if (state != READY) puts("无效操作");            else if (n > balance) puts("余额不足");            else if (n > cash) puts("现金不足");            else {                balance -= n;                cash -= n;                printf("%d\n", balance);            }        } else if (strcmp(cmd, "deposit") == 0) {            if (state != READY) puts("无效操作");            else {                int n = atoi(arg);                balance += n;                cash += n;                printf("%d\n", balance);            }        } else if (strcmp(cmd, "balance") == 0) {            if (state != READY) puts("无效操作");            else printf("%d\n", balance);        } else { /* eject */            if (state == IDLE) puts("无效操作");            else {                state = IDLE;                puts("已退卡");            }        }    }    printf("%d %d\n", balance, cash);    return 0;}
Craykonmain.cray · 117 行
첫줄 = 控制台.读行().去空白().分割();잔액 = 첫줄[0].转数字();비밀번호 = 첫줄[1]; // PIN은 0으로 시작할 수 있어 문자열로 둔다현금 = 첫줄[2].转数字();상태 = "idle"; // idle(카드 없음) → card(카드 들어옴) → ready(PIN 확인됨)틀린수 = 0; // 틀린 횟수: 카드를 뺐다 넣어도 이어진다가져감 = 假; // 세 번 틀려 기계가 카드를 가져갔나 p = 控制台.读行().去空白().分割();当 (p[0] != "quit"){    명령 = p[0];    如果 (명령 == "insert")    {        如果 (가져감)        {            控制台.输出("已停用");        }        否则 如果 (상태 != "idle")        {            控制台.输出("无效操作");        }        否则        {            상태 = "card";            控制台.输出("已插卡");        }    }    否则 如果 (명령 == "pin")    {        如果 (상태 != "card")        {            控制台.输出("无效操作");        }        否则 如果 (p[1] == 비밀번호)        {            상태 = "ready";            틀린수 = 0;            控制台.输出("确认");        }        否则        {            틀린수++;            如果 (틀린수 == 3)            {                가져감 = 真;                상태 = "idle";                控制台.输出("吞卡");            }            否则            {                控制台.输出("错误");            }        }    }    否则 如果 (명령 == "withdraw")    {        n = p[1].转数字();        如果 (상태 != "ready")        {            控制台.输出("无效操作");        }        否则 如果 (n > 잔액)        {            控制台.输出("余额不足");        }        否则 如果 (n > 현금)        {            控制台.输出("现金不足");        }        否则        {            잔액 -= n;            현금 -= n;            控制台.输出(잔액);        }    }    否则 如果 (명령 == "deposit")    {        如果 (상태 != "ready")        {            控制台.输出("无效操作");        }        否则        {            n = p[1].转数字();            잔액 += n;            현금 += n;            控制台.输出(잔액);        }    }    否则 如果 (명령 == "balance")    {        如果 (상태 != "ready")        {            控制台.输出("无效操作");        }        否则        {            控制台.输出(잔액);        }    }    否则    {        如果 (상태 == "idle")        {            控制台.输出("无效操作");        }        否则        {            상태 = "idle";            控制台.输出("已退卡");        }    }    p = 控制台.读行().去空白().分割();}控制台.输出(잔액 + " " + 현금);