알고리즘의 묘미랄까.. 다 풀고 남들의 코드를 보는데 나와 다른 부분이 있어 흥미로웠다.
즉, 내 알고리즘의 시간복잡도는 최악의 경우 키의 개수인 26 * 맵의 크기인 nm 이었고, 찾은 방법은 최악의 경우 nm이었다. 결국 상수곱이므로 크게 차이는 나지 않지만, 그래도 좀 더 좋은 알고리즘이 있다면 그 방법을 택하는게 좋은거니 찾은 방법을 기준으로 서술하겠다.
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
using namespace std;
int main() {
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
int t;
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
//map과 visited 초기화
char map[102][102];
bool visited[102][102];
memset(visited, false, sizeof(visited));
memset(map, '.', sizeof(map));
//map 입력 - 테두리를 제외해 1부터 n까지에 채운다
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> map[i][j];
}
}
// Key 설정
string key;
cin >> key;
bool keyArr[26] = {false};
if (key != "0") {
for (char c : key) {
keyArr[c - 'a'] = true;
}
}
// BFS
int move[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
queue<pair<int, int>> q;
queue<pair<int, int>> door[26];
q.push({0,0});
visited[0][0] = true;
int cnt = 0;
while (!q.empty()) {
int i = q.front().first;
int j = q.front().second;
q.pop();
for (auto& mv : move) {
int mi = i + mv[0];
int mj = j + mv[1];
if (mi < 0 || mi > n+1 || mj < 0 || mj > m+1) continue;
if (map[mi][mj] != '*' && !visited[mi][mj]) {
char next = map[mi][mj];
if (next == '$') {
cnt++;
}
else if ('A' <= next && next <= 'Z') { // 문을 만날 경우
if (!keyArr[next - 'A']) { // 키가 존재하지 않을 경우
door[next - 'A'].push({mi, mj});
continue;
}
}
else if ('a' <= next && next <= 'z') { // 키를 만날 경우
if (!keyArr[next - 'a']) {
keyArr[next - 'a'] = true;
while (!door[next - 'a'].empty()) {
q.push(door[next - 'a'].front());
door[next - 'a'].pop();
}
}
}
q.push({mi, mj});
visited[mi][mj] = true;
}
}
}
cout << cnt << '\n';
}
return 0;
}