Paizaのスキルチェック過去問「みんなでしりとり」を解いた話


がんばりました。
こちらは公開OKのやつです。

書いたコード

shiritori.py
# coding: utf-8

N,K,M = [int(i) for i in input().split()]
d_dict = {input() for i in range(K)}
m_list = [input() for i in range(M)]
n_list = [i+1 for i in range(N)]

n = 0
flg = 0

for i in range(len(m_list)):
    z = ""
    if m_list[i] in d_dict:
        d_dict.remove(m_list[i])
        if m_list[i][-1:] == "z":
            z = n_list[n]
            flg = 0
        elif flg == 1 and m_list[i-1][-1:] != m_list[i][:1]:
            z = n_list[n]
            flg = 0
        elif flg == 0:
            flg = 1
    else:
        z = n_list[n]
        flg = 0
    if flg == 1 or n == len(n_list)-1:
        if n >= len(n_list)-1:
            n = 0
        else:
            n += 1

    if z != "":
        n_list.remove(z)

print(len(n_list))
for i in n_list:
    print(i)

解説的ななにか

コード汚くてすまない…

最初の定義部分

最初の3行はInputされるやつをそれぞれ格納しているだけです。
d_dictで使ってもいい単語リストを格納(dictって書いてるけどこれ辞書型じゃなくね?)
m_listで発言されたものをリスト化
n_listで参加者の管理

n = 0は発言者の順番を管理するやつ
flg = 0は最初の人かどうかを管理するフラグ(0=最初の人、1=2番目以降の人)

For文部分

for文はm_listを主軸にしました。
このとき、for i in m_list:としないのがポイント。
コレをやると、条件である

最初の人以外の発言の頭文字は、直前の人の発言の最後の文字と一緒でなければならない。

の比較ができなかった。

発言と単語リストの比較

if m_list[i] in d_dict:で、発言した単語が単語リストにあるかどうかを調べます。
ヒットすれば、単語リストから該当単語をd_dict.remove(m_list[i])で削除します。
こうすることで、二重発言のチェックとそもそもリストにない単語を同時に見ることができます。
ヒットしなければ、無条件で発言者を脱落させ、flg0(最初の発言者)にします。
脱落者の処理については後述します。

末尾にzが含まれていないか確認

d_dictに含まれていてもzで終わる単語はNG扱いとなっているので、含まれていれば脱落させます。
末尾だけみればいいので、m_list[i][-1:] == "z"[-1:]部分で末尾だけスライスします。
コレは後述の末尾と先頭を比較する際にも使うテクです。

一個前の末尾と今の先頭の文字を比較する

まず、m_list[i-1][-1:] != m_list[i][:1]部分の解説をします。
この部分は前の単語と今の単語の末尾と先頭を比較するものです。
前述したfor i in m_list:としない理由がこれです。
単語を直接ぶちこむと比較できなくなってしまうため、for i in range(len(m_list))としたのです
スライスについてはもっと良い解説をしている方がいるはずですので、そちらで。
このまま使用すると、間違えた次の人にも適用されてしまうため先頭じゃないフラグflg=1の人のみを対象とするため、flg==1を追加して以下とします。
flg == 1 and m_list[i-1][-1:] != m_list[i][:1]

次の人へ

一折見終わったら次の人へパスします。
パスするには単純にn += 1をすれば回せます。
が、ここで2つ問題が発生します。
1つ目が、最後まで回ったときどうするのか。
2つ目が、脱落者の部分をどうするのか。
それを一気に解決するのが次の部分です。

if flg == 1 or n == len(n_list)-1:
    if n >= len(n_list)-1:
        n = 0
    else:
        n += 1

1つ目については
nlen(n_list)-1と同じになったら0にすることで解決します。
これ2個めのifいらないのでは…?
2つ目の部分については、
脱落させると順番がズレます。
次の人が今のnの位置に収まるので実は何もする必要がないです。
それ以外の場合n += 1します。

脱落者の処理

脱落処理でzに脱落者番号を格納しておき、その都度処理します。

if z != "":
    n_list.remove(z)

出力

最後に出力して終わりです。

print(len(n_list))
for i in n_list:
    print(i)

最後に

重複の管理と参加者の管理がミソなのかなと思います。

もっとこうしたらいいよっていうのがあったら教えて下さい