{ }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# で class の代わりに struct にすると値型なので取り出すたびにコピーが返り、入金が消えます。
振替は 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();}