Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- spring security
- nestjs
- 일급 컬렉션
- Spring
- factory
- synchronized
- 일급 객체
- OAuth 2.0
- middleware
- java
- builder
- lombok
- Volatile
- Dependency Injection
- Google OAuth
Archives
- Today
- Total
HJW's IT Blog
[Programmers] 수레 움직이기 [C++] 본문
문제 설명
n x m 크기 격자 모양의 퍼즐판이 주어집니다.
퍼즐판에는 빨간색 수레와 파란색 수레가 하나씩 존재합니다. 각 수레들은 자신의 시작 칸에서부터 자신의 도착 칸까지 이동해야 합니다.
모든 수레들을 각자의 도착 칸으로 이동시키면 퍼즐을 풀 수 있습니다.
당신은 각 턴마다 반드시 모든 수레를 상하좌우로 인접한 칸 중 한 칸으로 움직여야 합니다. 단, 수레를 움직일 때는 아래와 같은 규칙이 있습니다.
- 수레는 벽이나 격자 판 밖으로 움직일 수 없습니다.
- 수레는 자신이 방문했던 칸으로 움직일 수 없습니다.
- 자신의 도착 칸에 위치한 수레는 움직이지 않습니다. 계속 해당 칸에 고정해 놓아야 합니다.
- 동시에 두 수레를 같은 칸으로 움직일 수 없습니다.
- 수레끼리 자리를 바꾸며 움직일 수 없습니다.
예를 들어, 아래 그림처럼 n = 3, m = 2인 퍼즐판이 있습니다.
- 속이 빨간색인 원은 빨간색 수레를 나타냅니다.
- 속이 파란색인 원은 파란색 수레를 나타냅니다.
- 테두리가 빨간색인 원은 빨간색 수레의 도착 칸을 나타냅니다.
- 테두리가 파란색인 원은 파란색 수레의 도착 칸을 나타냅니다.
위 퍼즐판은 아래와 같은 순서로 3턴만에 풀 수 있습니다.
- 빨간색 사선이 처진 칸은 빨간색 수레가 방문했던 칸을 나타냅니다. 규칙에 따라 빨간색 수레는 빨간색 사선이 처진 칸(방문했던 칸)으로는 이동할 수 없습니다.
- 파란색 사선이 처진 칸은 파란색 수레가 방문했던 칸을 나타냅니다. 규칙에 따라 파란색 수레는 파란색 사선이 처진 칸(방문했던 칸)으로는 이동할 수 없습니다.
퍼즐판의 정보를 나타내는 2차원 정수 배열 maze가 매개변수로 주어집니다. 퍼즐을 푸는데 필요한 턴의 최솟값을 return 하도록 solution 함수를 완성해 주세요. 퍼즐을 풀 수 없는 경우 0을 return 해주세요.
제한사항
- 1 ≤ maze의 길이 (= 세로 길이) ≤ 4
- 1 ≤ maze[i]의 길이 (= 가로 길이) ≤ 4
- maze[i][j]는 0,1,2,3,4,5 중 하나의 값을 갖습니다.
0 빈칸 1 빨간 수레의 시작 칸 2 파란 수레의 시작 칸 3 빨간 수레의 도착 칸 4 파란 수레의 도착 칸 5 벽 - 빨간 수레의 시작 칸, 빨간 수레의 도착 칸, 파란 수레의 시작 칸, 파란 수레의 도착 칸은 퍼즐판에 1개씩 존재합니다.
입출력 예
maze result
[[1, 4], [0, 0], [2, 3]] | 3 |
[[1, 0, 2], [0, 0, 0], [5, 0 ,5], [4, 0, 3]] | 7 |
[[1, 5], [2, 5], [4, 5], [3, 5]] | 0 |
[[4, 1, 2, 3]] | 0 |
문제 분석
- nxm 크기의 격자 모양 퍼즐판에서 빨강, 파랑 수레를 각각 목적지로 최단 턴 수 내에
- 모든 턴마다 두 수레를 이동해야함 (목적지 도착 경우 제외)
- 벽 / 격자 밖으로는 이동 불가
- 방문했던 칸 재방문 불가(색별로)
- 수래의 두 위치가 동시에 바뀔 수 없다
- 격자의 크기가 작기 때문에 완전 탐색으로도 가능할 것
코드
#include <bits/stdc++.h>
using namespace std;
pair<int,int> RP, BP, RG, BG; // 빨강 시작점, 파랑 시작점, 빨강 목적지, 파랑 목적지
int n, m;
int ans = INT_MAX;
int dy[] = {1,-1,0,0};
int dx[] = {0,0,1,-1};
using namespace std;
bool possible(int x, int y, vector<vector<bool>>& visited, vector<vector<int>>& maze){
// 좌표에 대한 탐색 가능 여부 분별
if(x < 0 || y < 0 || x >= n || y >= m) return false;
if(maze[x][y] == 5) return false;
if(visited[x][y]) return false;
return true;
}
void dfs(vector<vector<int>>& maze,
vector<vector<bool>>& redVisit,
vector<vector<bool>>& blueVisit,
pair<int,int> red, pair<int,int> blue, int cnt){
// red = 현재 빨강 좌표, blue = 현재 파랑 좌표
if(cnt >= ans) return; // 탐색중인 깊이가 이미 구한 답보다 깊어지면 탐색 중단
if(RG == red && BG == blue){
ans = min(ans, cnt);
return;
}
for(int i = 0; i<4; i++){
pair<int,int> nextRed = {red.first + dx[i], red.second + dy[i]}; // 다음 빨강 좌표
if(red == RG){ // 이미 목적지에 도착 했다면 움직이지 않음
nextRed = RG;
}
else{
if(!possible(nextRed.first, nextRed.second, redVisit, maze)) continue;
}
for(int j = 0; j<4; j++){
pair<int,int> nextBlue = {blue.first + dx[j], blue.second + dy[j]};
if(blue == BG){
nextBlue = BG;
}
else{
if(!possible(nextBlue.first, nextBlue.second, blueVisit, maze)) continue;
}
if(nextRed == nextBlue || (red != RG && blue!=BG && red == nextBlue && nextRed == blue)) continue;
redVisit[nextRed.first][nextRed.second] = true;
blueVisit[nextBlue.first][nextBlue.second] = true;
dfs(maze, redVisit, blueVisit, nextRed, nextBlue, cnt + 1);
redVisit[nextRed.first][nextRed.second] = false;
blueVisit[nextBlue.first][nextBlue.second] = false;
}
}
}
int solution(vector<vector<int>> maze) {
for(int i = 0; i<maze.size(); i++){
for(int j = 0; j<maze[i].size(); j++){
if(maze[i][j] == 1) RP = {i,j};
else if(maze[i][j] == 2) BP = {i,j};
else if(maze[i][j] == 3) RG = {i,j};
else if(maze[i][j] == 4) BG = {i,j};
}
}
n = maze.size(), m = maze[0].size();
vector<vector<bool>> redVisited(n, vector<bool>(m, false));
vector<vector<bool>> blueVisited(n, vector<bool>(m, false));
redVisited[RP.first][RP.second] = true;
blueVisited[BP.first][BP.second] = true;
dfs(maze, redVisited, blueVisited, RP, BP, 0);
return (ans == INT_MAX) ? 0 : ans;
}
- redVisited, blueVisited 를 사용해 두 수레의 각각 방문 격자를 기록했다
- 2중 for문을 통해 빨간색, 파란색에 대해 dfs 를 수행하며, 문제에서 명시된 조건을 위반하는지 확인 했다
- 첫 격자 처리에 유의하자
'Algorithm' 카테고리의 다른 글
[Programmers] 연속된 부분 수열 [C++] (0) | 2024.08.26 |
---|---|
[Programmers] 요격 시스템 [C++] (0) | 2024.08.21 |
[Programmers] 석유 시추 [c++] (0) | 2024.08.01 |
[Programmers] 붕대 감기 [C++] (0) | 2024.08.01 |
[Programmers] 산 모양 타일링 [C++] (0) | 2024.07.31 |