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

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

AtCoder ABC 247 B - Unique Nicknames (5Q, 灰色, 200 点)

意外と頭がこんがらがる

問題概要

 N 人の人  1, 2, \dots, N がいて、人  i の名字は  S_{i}、名前は  T_{i} である。

各人にニックネームをつけたい。人  i のニックネーム  a_{i}

  •  a_{i} = S_{i} または  a_{i} = T_{i} である
  •  j = 1, 2, \dots, N かつ  j \neq i である任意の  j に対して、 a_{i} \neq S_{j} かつ  a_{i} \neq T_{j} である

という条件を満たす必要がある。このようなニックネームの割り当てが可能かどうかを判定せよ。

制約

  •  2 \le N \le 100

考えたこと

条件をよく見ると、ある人のニックネームをどうするかによって、他の人のニックネームの付け方に影響を与えることがない。よって、各人  i について  S_{i} T_{i} のいずれかが条件を満たすかどうかを調べれば良い。

 i のニックネームを  S_{i} にできるかを調べる方法

これは、次のように判定できる。

 j = 1, 2, \dots, N かつ  j \neq i である任意の  j に対して、 S_{i} \neq S_{j} かつ  S_{i} \neq T_{j} であるかどうかを調べる。

 i のニックネームを  T_{i} にできるかを調べる方法

これは、次のように判定できる。

 j = 1, 2, \dots, N かつ  j \neq i である任意の  j に対して、 T_{i} \neq S_{j} かつ  T_{i} \neq T_{j} であるかどうかを調べる。

まとめ

以上から、各人  i に対して、そのニックネームを  S_{i} にする場合と、 T_{i} にする場合のいずれかにできるかどうかを調べよう。

全員について「できる」ならば答えは "Yes"、そうでなければ答えは "No" となる。

この解法の計算量は  O(N^{2}) となる。

コード

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

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

    bool res = true;
    for (int i = 0; i < N; i++) {
        // check S[i]
        bool okS = true;
        for (int j = 0; j < N; j++) {
            if (j == i) continue;
            if (S[j] == S[i] || T[j] == S[i]) okS = false;
        }

        // check T[i]
        bool okT = true;
        for (int j = 0; j < N; j++) {
            if (j == i) continue;
            if (S[j] == T[i] || T[j] == T[i]) okT = false;
        }

        if (!okS && !okT) res = false;
    }
    cout << (res ? "Yes" : "No") << endl;
}