알고리즘

[C++] 백준 9328번 : 열쇠

88dldl 2024. 8. 10. 11:45

https://www.acmicpc.net/problem/9328

 

 

[접근 방식]

이 문제는 지금은 문을 열지 못하지만 나중에 열쇠를 획득하게 될수도 있다는 중요한 사실이 있었다.

 

처음에는 dfs로 접근해보았는데 시간초과가 떴었다. 

-> 열 수 없는 문 위치를 기억하는 Queue와 BFS를 진행할 Queue를 사용해 문제를 해결한다.

=> 가장자리에서 모두 접근가능하기 때문에 입력받는 지도를 둘러싸는 칸이 하나 더 있다고 생각하여 문제를 해결한다. 

 

 

[코드]

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;

int h,w,maxnum;
bool key[26]; 
bool visit[102][102];
char v[102][102];

int dy[4] = {1,0,-1,0};
int dx[4] = {0,-1,0,1};


void bfs(int x,int y){
    queue<pair<int,int>> q;
    queue<pair<int,int>> door[26];
    q.push(make_pair(x,y));

    visit[x][y] = true;
    
    while(!q.empty()){
        int tmpx = q.front().first;
        int tmpy = q.front().second;
        
        q.pop();

        for(int i=0;i<4;i++){
            int nx = tmpx + dx[i];
            int ny = tmpy + dy[i];
            
            if(nx<0 ||nx>h+1|| ny<0 || ny>w+1 ) continue;
            if(v[nx][ny] =='*' || visit[nx][ny]) continue ;
            
            visit[nx][ny] = true;
            
            // 대문자 
            if(v[nx][ny]>='A' && v[nx][ny]<='Z'){
                if(key[v[nx][ny]-'A']) q.push(make_pair(nx,ny)); // 키 보유
                else door[v[nx][ny]-'A'].push(make_pair(nx,ny)); // 없으면 문 위치 기억 
            }
            // 소문자 
            else if(v[nx][ny]>='a' && v[nx][ny]<='z'){
                q.push(make_pair(nx,ny)); // 키 보유
                if(!key[v[nx][ny]-'a']){
                    key[v[nx][ny]-'a'] = true;
                    // 키를 찾았으니까 이동가능
                    while(!door[v[nx][ny]-'a'].empty()){
                        q.push(door[v[nx][ny]-'a'].front());
                        door[v[nx][ny]-'a'].pop();
                    }
                }
            }
            else{
                q.push(make_pair(nx,ny));
                if(v[nx][ny]=='$') maxnum++;
            }
        }
        
    }
}
        
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    int t;
    cin>>t;
    while(t--){
        memset(key,false,sizeof(key));
        memset(visit,false,sizeof(visit));
        memset(v,0,sizeof(v));
        maxnum = 0;

        cin>>h>>w;
        
        //지도
        for(int i=1;i<=h;i++){
            for(int j=1;j<=w;j++){
                cin>>v[i][j];
            }
        }

        //키
        string num;
        cin>>num;
        for (int i = 0; i < num.length(); i++) {
            if(num[i]=='0') continue;    
            key[num[i] - 'a'] = true;
        }

        bfs(0,0);

        cout<<maxnum<<"\n"; 
    }

    return 0;
}