けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 045 B - 3人でカードゲームイージー (5Q, 茶色, 200 点)

愚直シミュレーション問題!

問題概要

A さん、B さん、C さんの 3 人が以下のようなカードゲームをプレイしています。

最初、3 人はそれぞれ 'a', 'b', 'c' いずれかの文字が書かれたカードを、何枚か持っている。これらは入力で与えられた順番に持っており、途中で並べ替えたりしない。

A さんのターンから始まる。現在自分のターンである人がカードを 1 枚以上持っているならば、そのうち先頭のカードを捨てる。その後、捨てられたカードに書かれているアルファベットと同じ名前の人のターンとなる。

現在自分のターンである人がカードを 1 枚も持っていないならば、その人がゲームの勝者となり、ゲームは終了する。

3 人が最初に持っているカードを表す文字列  S_{A}, S_{B}, S_{C} が与えられる。各文字列の  i 番目の文字が、上から  i 枚目のカードの書かれたアルファベットを表す。最終的に誰がこのゲームの勝者となるかを求めよ。

制約

  •  1 \le |S_{A}|, |S_{B}|, |S_{C}| \le 100

考えたこと

プレイヤーの手持ちのカードが先頭から捨てられていく様子をシミュレーションするときの手法として、添字を進めていくという方法が典型的だ。

たとえば、文字列 "acac" に対して、先頭にあるカードを表す添字 iter を用意する。まだ 1 枚も捨てられていないとき、iter = 0 とする。

先頭のカードを捨てたとき、文字列を "acac" の先頭の文字を消して "cac" とする代わりに、iter を 1 増やして iter = 1 とするのだ。そうすることで、文字列を直接変更することなく「先頭のカードを捨てた」ことを表現できる。

今回の問題では、3 つの文字列のそれぞれについて、添字 iter[0], iter[1], iter[2] を用意してシミュレーションすればよい。下のコードのように実装できる。

コード

#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<string> S(3);
    for (int i = 0; i < 3; i++) cin >> S[i];

    // 現在 player が誰か、各プレイヤーのカードがどこまで進んでいるか
    int player = 0;
    vector<int> iter(3, 0);

    // カードがなくなった人が指定されるまで
    while (iter[player] < S[player].size()) {
        char next_player = S[player][iter[player]];
        iter[player]++;  // player のカードを進める
        if (next_player == 'a') player = 0;
        else if (next_player == 'b') player = 1;
        else player = 2;
    }
    cout << (char)('A' + player) << endl;
}