문제
https://school.programmers.co.kr/learn/courses/30/lessons/250134
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 개요
이 문제는 n x m 크기의 격자 모양 퍼즐판에서 두 개의 수레(빨간색과 파란색)를 각각 자신의 도착 칸으로 이동시키는 퍼즐을 푸는 문제입니다. 수레들은 상하좌우로 한 칸씩 이동하며, 여러 제약 조건을 준수해야 합니다.
- 수레는 벽이나 격자 판 밖으로 움직일 수 없습니다.
- 수레는 자신이 방문했던 칸으로 움직일 수 없습니다.
- 자신의 도착 칸에 위치한 수레는 움직이지 않습니다.
- 계속 해당 칸에 고정해 놓아야 합니다. 동시에 두 수레를 같은 칸으로 움직일 수 없습니다.
- 수레끼리 자리를 바꾸며 움직일 수 없습니다.
접근 방법
- 초기 상태 설정
- 퍼즐판(maze)를 순회하여 빨간 수레의 시작 위치(curRed)와 파란 수레의 시작 위치(curBlue)를 찾습니다.
- 각 수레의 방문 여부를 표시하기 위한 3차원 배열 v를 선언합니다.
- v[i][j][0]: 빨간 수레가 (i, j)를 방문했는지.
- v[i][j][1]: 파란 수레가 (i, j)를 방문했는지.
- min: 최소 턴 수를 추적하기 위한 변수. 초기값은 Integer.MAX_VALUE로 설정합니다.
- 백트래킹 함수 정의
- bt(maze, cnt, curRed, curBlue):
- cnt: 현재까지 소모된 턴 수.
- curRed, curBlue: 현재 빨간/파란 수레의 위치.
- 종료 조건:
- 빨간 수레와 파란 수레가 모두 목표 지점에 도달했을 경우 min 값을 업데이트하고 종료합니다.
- 다음 상태 탐색:
- 두 수레가 상하좌우로 이동 가능한 모든 조합을 탐색합니다.
- 각 이동이 유효한지 판단하기 위해 isPossible 함수를 호출합니다.
- 이동 후, 현재 이동을 기록하고 다음 턴으로 재귀 호출합니다.
- 재귀 호출이 끝나면 이동 기록을 복구하고 탐색을 계속 진행합니다.
- bt(maze, cnt, curRed, curBlue):
- 이동 가능 여부 판단 함수
- isPossible(maze, curRed, curBlue, red, blue):
- 다음 조건을 확인하여 두 수레가 주어진 위치로 이동 가능한지 판단합니다.
- 퍼즐판 경계 확인: 다음 위치가 퍼즐판 바깥인지.
- 방문 여부: 아직 방문하지 않은 위치인지.
- 벽 확인: 이동하려는 칸이 벽인지.
- 수레 간 충돌 확인: 두 수레가 동일한 칸으로 이동하거나 서로 자리를 바꾸는지.
- 다음 조건을 확인하여 두 수레가 주어진 위치로 이동 가능한지 판단합니다.
- 위 조건 중 하나라도 만족하지 않으면 false를 반환합니다.
- isPossible(maze, curRed, curBlue, red, blue):
고려사항
- 수레 간 충돌 규칙 처리
두 수레가 같은 칸으로 이동하거나, 서로 자리를 바꾸는 상황은 반드시 방지해야 합니다. - 도착 후 움직임 제한
목표 지점에 도달한 수레는 이후 움직임에서 제외하고 고정해 둡니다. - 백트래킹 최적화
이미 방문한 상태를 재탐색하지 않도록 방문 기록(v)을 효과적으로 관리합니다. - 퍼즐을 풀 수 없는 경우 처리
모든 가능한 이동을 탐색했음에도 목표에 도달하지 못한 경우, 0을 반환합니다.
코드
import java.util.*;
class Solution {
static int min = Integer.MAX_VALUE;
static int[] dr = {-1, 1, 0, 0};
static int[] dc = {0, 0, -1, 1};
static boolean[][][] v; //0=red, 1=blue
static boolean finishedRed = false;
static boolean finishedBlue = false;
public int solution(int[][] maze) {
int answer = 0;
v = new boolean[maze.length][maze[0].length][2];
Pos curRed = null, curBlue = null;
for(int i=0; i<maze.length; i++) {
for(int j=0; j<maze[0].length; j++) {
if(maze[i][j] == 1) curRed = new Pos(i,j);
if(maze[i][j] == 2) curBlue = new Pos(i,j);
}
}
v[curRed.r][curRed.c][0] = true;
v[curBlue.r][curBlue.c][1] = true;
bt(maze, 0, curRed, curBlue);
answer = min == Integer.MAX_VALUE ? 0 : min;
return answer;
}
public void bt(int[][] maze, int cnt, Pos curRed, Pos curBlue) {
if(finishedRed && finishedBlue) {
min = Math.min(cnt, min);
return;
}
for(int i=0; i<4; i++) {
for(int j=0; j<4; j++) {
Pos red = finishedRed ? curRed : new Pos(curRed.r + dr[i], curRed.c + dc[i]);
Pos blue = finishedBlue ? curBlue : new Pos(curBlue.r + dr[j], curBlue.c + dc[j]);
if(isPossible(maze, curRed, curBlue, red, blue)) {
v[red.r][red.c][0] = true;
v[blue.r][blue.c][1] = true;
if(maze[red.r][red.c] == 3) finishedRed = true;
if(maze[blue.r][blue.c] == 4) finishedBlue = true;
bt(maze, cnt+1, red, blue);
v[red.r][red.c][0] = false;
v[blue.r][blue.c][1] = false;
finishedRed = false;
finishedBlue = false;
}
}
}
}
public boolean isPossible(int[][] maze, Pos curRed, Pos curBlue, Pos red, Pos blue) {
//판 밖으로 움직일 때
if(red.r<0 || red.c<0 || red.r>=maze.length || red.c>=maze[0].length) return false;
if(blue.r<0 || blue.c<0 || blue.r>=maze.length || blue.c>=maze[0].length) return false;
//도착하지 않았으면서 이미 방문했을 때
if(!finishedRed && v[red.r][red.c][0]) return false;
if(!finishedBlue && v[blue.r][blue.c][1]) return false;
//움직인 칸이 벽일 때
if(maze[red.r][red.c] == 5) return false;
if(maze[blue.r][blue.c] == 5) return false;
//수레끼리 자리를 바꿨을 때
if((red.r == curBlue.r && red.c == curBlue.c) && (blue.r == curRed.r && blue.c == curRed.c)) return false;
//같은 자리일 때
if(red.r == blue.r && red.c == blue.c) return false;
return true;
}
static class Pos{
int r, c;
public Pos(int r, int c) {
this.r = r;
this.c = c;
}
}
}
'문제 > 프로그래머스' 카테고리의 다른 글
[프로그래머스] 무인도 여행 - Java (0) | 2024.11.30 |
---|---|
[프로그래머스] 미로 탈출 - Java (0) | 2024.11.30 |
[프로그래머스] [PCCP 기출문제] 4번 / 수식 복원하기 - Java (0) | 2024.11.26 |
[프로그래머스] [PCCP 기출문제] 1번 / 동영상 재생기도움말 - Java (0) | 2024.11.26 |
[프로그래머스] 문자열 나누기 - Java (0) | 2024.11.24 |