{ }codelper
类方法P0078

银行账户对象

把账户写成一个类。
账户对象以姓名、余额、被拒绝次数为字段,只通过存款(deposit)、取款(withdraw)、转账(transfer)方法改变余额。
第一行给出账户数 n,接下来 n 行给出 "姓名 初始余额",再下一行给出命令数 q,接下来 q 行每行一个命令。
命令有三种:"deposit 姓名 x" 向该账户存入 x。"withdraw 姓名 x" 从该账户取出 x。"transfer 转出姓名 转入姓名 x" 从转出账户取出 x 并存入转入账户。
若要取出的金额 x 大于余额,该取款或转账被拒绝:所有账户余额都不变,只有要取钱的账户(转账时为转出账户)的拒绝次数加 1。
x 等于余额时不拒绝(余额变为 0)。
按顺序处理完所有命令后,按账户在输入中出现的顺序,每个账户输出一行 "姓名 余额 拒绝次数"。

输入
1 ≤ n ≤ 1000,1 ≤ q ≤ 5000。
姓名为 1 到 10 个小写英文字母或数字,互不相同。
0 ≤ 初始余额 ≤ 1,000,000,000,1 ≤ x ≤ 1,000,000,000(整数)。
命令中的姓名都是已有账户,转账的两个姓名不同
输出
n 行,每行姓名、余额、拒绝次数用一个空格分隔(余额最多可增长到约 5 万亿)
样例 1 · stdin
3
mina 100
jun 50
seo 0
5
withdraw mina 100
transfer jun seo 30
withdraw jun 21
deposit mina 7
transfer seo mina 31
stdout
mina 7 0
jun 20 1
seo 30 1
main.py
输入(stdin)

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

$ 就绪

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

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

本题只接受有类的 Python、JavaScript、TypeScript、Java、C#、C++(C 没有类,Craykon 还不能定义类)。
第一个陷阱是拒绝的边界:与余额相等的金额可以取出,所以只在 amount > balance 时拒绝,写成 >= 就错了。
第二个是余额的大小:向一个账户存 10 亿共 5000 次约为 5 万亿,Java int、C# int、C++ int(约 21 亿为止)会悄悄溢出。
Java、C# 用 long,C++ 用 long long;Python int 没有上限,JS、TS 的 number 在 2^53 以内精确,所以没问题。
第三个是取出对象时会不会产生副本。
Python、JS、TS、Java 的对象和 C# 的 class 都按引用处理,修改从字典取出的账户就会改变原账户。
但 C++ 的 Account acc = accounts[i]; 会整体复制对象,必须写成引用 Account& acc;C# 若用 struct 代替 class,就是值类型,每次取出都得到副本,存款就丢失了。
让转账只在 withdraw 成功时才调用 deposit,拒绝规则就只需写在一处。

Pythonmain.py · 47 行
import sys  class Account:    def __init__(self, name, balance):        self.name = name        self.balance = balance        self.refused = 0     def deposit(self, amount):        self.balance += amount     def withdraw(self, amount):        """잔액이 모자라면 거절하고 False를 돌려준다."""        if amount > self.balance:            self.refused += 1            return False        self.balance -= amount        return True     def transfer(self, other, amount):        if self.withdraw(amount):            other.deposit(amount)  lines = sys.stdin.read().split("\n")n = int(lines[0])accounts = []by_name = {}for line in lines[1:n + 1]:    name, balance = line.split()    acc = Account(name, int(balance))    accounts.append(acc)    by_name[name] = acc q = int(lines[n + 1])for line in lines[n + 2:n + 2 + q]:    p = line.split()    if p[0] == "deposit":        by_name[p[1]].deposit(int(p[2]))    elif p[0] == "withdraw":        by_name[p[1]].withdraw(int(p[2]))    else:        by_name[p[1]].transfer(by_name[p[2]], int(p[3])) for acc in accounts:    print(acc.name, acc.balance, acc.refused)
JavaScriptmain.js · 46 行
class Account {  constructor(name, balance) {    this.name = name;    this.balance = balance;    this.refused = 0;  }   deposit(amount) {    this.balance += amount;  }   // 잔액이 모자라면 거절하고 false를 돌려준다  withdraw(amount) {    if (amount > this.balance) {      this.refused++;      return false;    }    this.balance -= amount;    return true;  }   transfer(other, amount) {    if (this.withdraw(amount)) other.deposit(amount);  }} const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const accounts = [];const byName = new Map();for (let i = 1; i <= n; i++) {  const [name, balance] = lines[i].trim().split(" ");  const acc = new Account(name, Number(balance));  accounts.push(acc);  byName.set(name, acc);} const q = Number(lines[n + 1]);for (let i = n + 2; i < n + 2 + q; i++) {  const p = lines[i].trim().split(" ");  if (p[0] === "deposit") byName.get(p[1]).deposit(Number(p[2]));  else if (p[0] === "withdraw") byName.get(p[1]).withdraw(Number(p[2]));  else byName.get(p[1]).transfer(byName.get(p[2]), Number(p[3]));} console.log(accounts.map((a) => `${a.name} ${a.balance} ${a.refused}`).join("\n"));
TypeScriptmain.ts · 56 行
import { readFileSync } from "node:fs"; class Account {  readonly name: string;  private balance: number;  private refused = 0;   constructor(name: string, balance: number) {    this.name = name;    this.balance = balance;  }   deposit(amount: number): void {    this.balance += amount;  }   // 잔액이 모자라면 거절하고 false를 돌려준다  withdraw(amount: number): boolean {    if (amount > this.balance) {      this.refused++;      return false;    }    this.balance -= amount;    return true;  }   transfer(other: Account, amount: number): void {    if (this.withdraw(amount)) other.deposit(amount);  }   describe(): string {    return `${this.name} ${this.balance} ${this.refused}`;  }} const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);const accounts: Account[] = [];const byName = new Map<string, Account>();for (let i = 1; i <= n; i++) {  const [name, balance] = lines[i].trim().split(" ");  const acc = new Account(name, Number(balance));  accounts.push(acc);  byName.set(name, acc);} const q: number = Number(lines[n + 1]);for (let i = n + 2; i < n + 2 + q; i++) {  const p: string[] = lines[i].trim().split(" ");  const acc = byName.get(p[1])!;  if (p[0] === "deposit") acc.deposit(Number(p[2]));  else if (p[0] === "withdraw") acc.withdraw(Number(p[2]));  else acc.transfer(byName.get(p[2])!, Number(p[3]));} console.log(accounts.map((a) => a.describe()).join("\n"));
JavaMain.java · 66 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map; class Account {    private final String name;    private long balance; // 5000번 넣으면 int(약 21억)를 넘는다    private int refused = 0;     Account(String name, long balance) {        this.name = name;        this.balance = balance;    }     void deposit(long amount) { balance += amount; }     /** 잔액이 모자라면 거절하고 false를 돌려준다. */    boolean withdraw(long amount) {        if (amount > balance) {            refused++;            return false;        }        balance -= amount;        return true;    }     void transfer(Account other, long amount) {        if (withdraw(amount)) other.deposit(amount);    }     String describe() { return name + " " + balance + " " + refused; }} 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());        List<Account> accounts = new ArrayList<>();        Map<String, Account> byName = new HashMap<>();        for (int i = 0; i < n; i++) {            String[] p = in.readLine().trim().split(" ");            Account acc = new Account(p[0], Long.parseLong(p[1]));            accounts.add(acc);            byName.put(p[0], acc);        }         int q = Integer.parseInt(in.readLine().trim());        for (int i = 0; i < q; i++) {            String[] p = in.readLine().trim().split(" ");            Account acc = byName.get(p[1]);            switch (p[0]) {                case "deposit" -> acc.deposit(Long.parseLong(p[2]));                case "withdraw" -> acc.withdraw(Long.parseLong(p[2]));                default -> acc.transfer(byName.get(p[2]), Long.parseLong(p[3]));            }        }         StringBuilder out = new StringBuilder();        for (Account acc : accounts) out.append(acc.describe()).append('\n');        System.out.print(out);    }}
C#Main.cs · 69 行
using System;using System.Collections.Generic;using System.Text; class Account{    public string Name { get; }    public long Balance { get; private set; } // 5000번 넣으면 int(약 21억)를 넘는다    public int Refused { get; private set; }     public Account(string name, long balance)    {        Name = name;        Balance = balance;    }     public void Deposit(long amount) => Balance += amount;     // 잔액이 모자라면 거절하고 false를 돌려준다    public bool Withdraw(long amount)    {        if (amount > Balance)        {            Refused++;            return false;        }        Balance -= amount;        return true;    }     public void Transfer(Account other, long amount)    {        if (Withdraw(amount)) other.Deposit(amount);    }} class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine());        var accounts = new List<Account>();        var byName = new Dictionary<string, Account>();        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            var acc = new Account(p[0], long.Parse(p[1]));            accounts.Add(acc);            byName[p[0]] = acc;        }         int q = int.Parse(Console.ReadLine());        for (int i = 0; i < q; i++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            Account acc = byName[p[1]];            switch (p[0])            {                case "deposit": acc.Deposit(long.Parse(p[2])); break;                case "withdraw": acc.Withdraw(long.Parse(p[2])); break;                default: acc.Transfer(byName[p[2]], long.Parse(p[3])); break;            }        }         var sb = new StringBuilder();        foreach (var acc in accounts) sb.Append($"{acc.Name} {acc.Balance} {acc.Refused}\n");        Console.Write(sb);    }}
C++main.cpp · 68 行
#include <iostream>#include <string>#include <unordered_map>#include <utility>#include <vector> class Account {public:    Account(std::string name, long long balance) : name_(std::move(name)), balance_(balance) {}     void deposit(long long amount) { balance_ += amount; }     // 잔액이 모자라면 거절하고 false를 돌려준다    bool withdraw(long long amount) {        if (amount > balance_) {            refused_++;            return false;        }        balance_ -= amount;        return true;    }     void transfer(Account& other, long long amount) {        if (withdraw(amount)) other.deposit(amount);    }     void print() const { std::cout << name_ << ' ' << balance_ << ' ' << refused_ << '\n'; } private:    std::string name_;    long long balance_; // 5000번 넣으면 int(약 21억)를 넘는다    int refused_ = 0;}; int main() {    std::ios::sync_with_stdio(false);    int n;    std::cin >> n;    std::vector<Account> accounts;    std::unordered_map<std::string, int> index; // 이름 → 자리(벡터가 자라도 바뀌지 않는다)    for (int i = 0; i < n; i++) {        std::string name;        long long balance;        std::cin >> name >> balance;        accounts.emplace_back(name, balance);        index[name] = i;    }     int q;    std::cin >> q;    for (int i = 0; i < q; i++) {        std::string cmd, a;        long long x;        std::cin >> cmd >> a;        Account& acc = accounts[index[a]]; // &를 빼면 복사본이 바뀐다        if (cmd == "transfer") {            std::string b;            std::cin >> b >> x;            acc.transfer(accounts[index[b]], x);        } else {            std::cin >> x;            if (cmd == "deposit") acc.deposit(x);            else acc.withdraw(x);        }    }     for (const Account& acc : accounts) acc.print();}