코딩테스트/그래프|트리

[BFS+DP] 프로그래머스 리틀 프렌즈 사천성 C++

유(YOO) 2023. 4. 15. 00:12

 

https://school.programmers.co.kr/learn/courses/30/lessons/1836

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

#include <string>
#include <vector>
#include <queue>
#include <map>

using namespace std;

struct pos {
    int x, y;
};

int M, N;
vector<string> Board;

bool bfs(char alp, pos p) {
    int dx[4] = {0, 1, 0, -1}; // 상우하좌
    int dy[4] = {-1, 0, 1, 0};
    
    int turn[M][N]; // 방향 꺾기 최소 횟수
    fill(&turn[0][0], &turn[M-1][N], 2); // INF로 초기화
    
    queue<vector<int>> q;
    q.push({p.x, p.y, -1}); // 이전 방향
    turn[p.y][p.x] = 0; // 초기화
    while(!q.empty()) {
        vector<int> now = q.front();
        q.pop();
        
        if (Board[now[1]][now[0]] == alp) {
            if ((now[0] != p.x) || (now[1] != p.y)) { // 같은 알파벳 타일 찾음(출발지X)
                Board[p.y][p.x] = '.';// 보드 수정
                Board[now[1]][now[0]] = '.';
                return true;
            }
        }

        for(int i=0; i<4; i++) {
            int newX = now[0] + dx[i];
            int newY = now[1] + dy[i];
            int dir = now[2];
            int cnt = turn[now[1]][now[0]];
            
            if ((newX < 0) || (newY < 0) || (newX >= N) || (newY >= M)) continue;
            if ((Board[newY][newX] != '.') && (Board[newY][newX] != alp)) continue;
            
            if ((dir != -1) && (i != dir)) cnt++; // 방향 꺾기
            if (cnt > 1) continue; // 방향 꺾기 2회 이상
            if (turn[newY][newX] >= cnt) { // DP 필요
                q.push({newX, newY, i});
                turn[newY][newX] = cnt;
            }
        }
    }
    return false;
}

string solution(int m, int n, vector<string> board) {
    M = m;
    N = n;
    Board = board;
    map<char, pos> mp; // 알파벳 -> 위치

    // 알파벳 -> 위치
    for(int i=0; i<m; i++) {
        for(int j=0; j<n; j++) {
            if ((board[i][j] != '.') && (board[i][j] != '*')) mp[board[i][j]] = {j, i};
        }
    }
    
    string answer = "";
    while(true) {
        bool isPossible = false;
        for(auto m : mp) { // 카드 알파벳 순서대로 확인 반복
            if (bfs(m.first, m.second)) {
                isPossible = true;
                answer += m.first;
                mp.erase(m.first);
                break;
            }
        }
        
        if (isPossible) continue;
        if (mp.empty()) return answer;
        else return "IMPOSSIBLE";
    }
}