저번에 배웠던 교훈에 따라 효율성 신경쓰지말고 먼저 정답을 만들기에 집중했습니다.
(AC는 받았지만 속도 느리다는 점 미리 밑밥 깔고 갑니다...ㅎㅎ)
문제를 요약하면, ''단어 N개 중 알파벳 K개로 표현할 수 있는 단어의 최대 개수를 구하세요'' 입니다.
문제 과정을 요약하면 다음과 같습니다.
'최대 개수'를 알기 위해서는 모든 조합을 검사해야 하므로 bruteforce 문제입니다.
Bruteforce이므로 탐색해야하는 범위 자체를 줄일 수는 없지만, 조금 효율적으로 조합을 구할 수 있는 방법이 있습니다.
바로, "남극언어의 모든 단어는 "anta"로 시작되고, "tica"로 끝난다"라는 조건 덕분입니다.
단어를 최대한 읽기 위해서는 무조건 a, c, i, n, t
5글자를 알아야 합니다.
K
가 5
보다 작다면 무조건 읽을 수 있는 단어 개수는 0
입니다.a, c, i, n, t
는 true
로 놓고 출발합니다.저는 alphabet[26]
과 perm[26]
이라는 bool
타입 배열 2개를 만들었습니다.
alphabet[26]
: a, c, i, n, t
5글자를 항상 true
로 가지고 있는 배열입니다.perm[26]
: 고른 K-5개의 알파벳을 false
로 가지고 있는 배열입니다.perm[]
에 저장된 K-5
개의 알파벳이 alphabet
과 겹치는 경우는 continue;
로 생략하도록 만들었습니다.각 단어를 검사할 때 단어 길이가 짧기 때문에 for문
을 이용해서 검사했습니다.
하지만, 비트마스크를 이용하는 방법도 있습니다.
i
번째 단어에 포함된 글자에 해당하는 비트를 set 해줍니다.#include <iostream>
#include <vector>
#include <algorithm>
#define NUMALPHA 26
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
using namespace std;
int main() {
ios::sync_with_stdio(false), cin.tie(NULL);
int N, K, ans = 0;
cin >> N >> K;
vector<string> words(N);
for (int i = 0; i < N; ++i) cin >> words[i];
if (K < 5) { cout << ans; return 0; }
vector<bool> alphabet(NUMALPHA, false);
alphabet[0] = alphabet[2] = alphabet[8] = alphabet[13] = alphabet[19] = true;
vector<bool> perm(NUMALPHA, true);
for (int i = 0; i < K - 5; ++i) perm[i] = false;
do {
int cnt = 0;
if (!perm[0] || !perm[2] || !perm[8] || !perm[13] || !perm[19]) continue;
for (int i = 0; i < NUMALPHA; ++i) // check readable alphabets.
if (!perm[i]) alphabet[i] = true;
for (const string& word : words) {
bool flag = true;
for (size_t i = 0; i < word.length(); ++i) // Is the word readable?
if (!alphabet[word[i] - 'a']) { flag = false; break; }
if (flag) cnt++;
}
for (int i = 0; i < NUMALPHA; ++i) // uncheck alphabets for next loop.
if (!perm[i]) alphabet[i] = false;
ans = max(ans, cnt);
} while (next_permutation(begin(perm), end(perm)));
cout << ans;
}