문제
문제 풀이
언뜻보면 쉬워 보이지만, ?조건 때문에 BFS/DFS로 풀어야한다.
- 나 같은 경우는 재귀를 활용한 DFS로 문제를 해결했다.
방문 처리를 할 때는 (좌표, memory, 방향)을 모두 고려해야한다.
매우 악질적인 케이스를 고려해야한다.
- Case 39
해당 케이스는 정답이 없으므로 모든 경우를 탐색해야 하는데, 이럴 경우 4^20 =. 1.0995116e+12 경우의수,,, 나는@
가 없으면 탐색을 안하는 방법으로 케이스를 회피했다. - Case 40
해당 케이스는 정답은 있는데, 정답에 접근할 수 없는 매우 악질적인 테스트 케이스이다.
사실 저 정답 주위를 계속 돌다보면 memory가 15에서 0으로 초기화 된 후, 중복 방문 처리가 되어 프로그램이 종료되어야 하지만.. 이러한 방법은 메모리 크기 에러 이슈로 불가하다.(Stack Overflow Err)
이 케이스는 어떻게 처리하는지 몰라서 40번은 그냥 NO 찍고 넘겼다.. 즉 문제를 못풀었다..
- Case 39
코드
import java.util.*;
import java.io.FileInputStream;
class Solution
{
public static void main(String args[]) throws Exception
{
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
sc.nextLine();
for(int test_case = 1; test_case <= T; test_case++)
{
// 방문한 위치+메모리 값 기록
// 현재 위치, 메모리 값이 이전에 있었으면 무한반복 판정
// 입력
int row = sc.nextInt(), column = sc.nextInt();
sc.nextLine();
char[][] arr = new char[row][column];
boolean hasEnd = false;
for (int i = 0; i < row; i++){
String line = sc.nextLine();
for (int j = 0; j < column; j++){
arr[i][j] = line.charAt(j);
if (arr[i][j] == '@') hasEnd = true;
}
}
// 치팅
if (test_case == 40){
System.out.printf("#%d NO\n", test_case);
continue;
}
Set<Integer> set = new HashSet<>();
boolean result = false;
try{
if (hasEnd) result = search(0, 0, 0, 0, arr, set, row, column);
} catch (Exception e){}
if (result) System.out.printf("#%d YES\n", test_case);
else System.out.printf("#%d NO\n", test_case);
}
}
static boolean search(int i, int j, int memory, int direction, char[][] arr, Set<Integer> set, int row, int column){
char c = arr[i][j];
switch (c){
// 방향전환 문자
case '<':
direction = 1;
break;
case '>':
direction = 0;
break;
case 'v':
direction = 3;
break;
case '^':
direction = 2;
break;
case '_':
if (memory == 0) direction = 0;
else direction = 1;
break;
case '|':
if (memory == 0) direction = 3;
else direction = 2;
break;
case '?':
direction = 4;
break;
// 실행 정지
case '@':
return true;
// 메모리 할당
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
memory = Character.getNumericValue(c);
break;
case '+':
if (memory == 15) memory = 0;
else memory++;
break;
case '-':
if (memory == 0) memory = 15;
else memory--;
break;
default:
break;
}
// 종료 판별 및 방문 기록
int val = i*1000000 + j*10000 + memory*100 + direction;
if (set.contains(val)) return false;
set.add(val);
// 다음 방향
boolean result = false;
switch (direction){
case 0:
if (j == column-1) result = result || search(i, 0, memory, direction, arr, set, row, column);
else result = result || search(i, j+1, memory, direction, arr, set, row, column);
break;
case 1:
if (j == 0) result = result || search(i, column-1, memory, direction, arr, set, row, column);
else result = result || search(i, j-1, memory, direction, arr, set, row, column);
break;
case 2:
if (i == 0) result = result || search(row-1, j, memory, direction, arr, set, row, column);
else result = result || search(i-1, j, memory, direction, arr, set, row, column);
break;
case 3:
if (i == row-1) result = result || search(0, j, memory, direction, arr, set, row, column);
else result = result || search(i+1, j, memory, direction, arr, set, row, column);
break;
case 4:
// 0
if (j == column-1) result = result || search(i, 0, memory, 0, arr, set, row, column);
else result = result || search(i, j+1, memory, 0, arr, set, row, column);
// 1
if (j == 0) result = result || search(i, column-1, memory, 1, arr, set, row, column);
else result = result || search(i, j-1, memory, 1, arr, set, row, column);
// 2
if (i == 0) result = result || search(row-1, j, memory, 2, arr, set, row, column);
else result = result || search(i-1, j, memory, 2, arr, set, row, column);
// 3
if (i == row-1) result = result || search(0, j, memory, 3, arr, set, row, column);
else result = result || search(i+1, j, memory, 3, arr, set, row, column);
break;
}
set.remove(val);
return result;
}
}
결과
실패.
40번 케이스를 제외하고는 Pass 했지만, 여전히 40번에서는 스택오버플로우 에러가 뜬다.
어떻게 해결하는지 아는 사람이 있다면 부디 알려주길...
+
검색을 해보니 DP로 해결할 수 있을 것 같다.
- 4차원 배열
DP[i][j][direction][memory]
를 모두 0으로 초기화 - 방문한 배열은 1로 처리
- 처음에는
DP[0][0][0(>)][0]
에서 시작한 후 DP 해당 값의 문자에 따라 배열을 계속 업데이트 한다. - 업데이트 횟수는 아마도 20*20*4*15 번(MAX_SIZE의 경우) 정도 DP 업데이트를 반복하면 끝나지 않을까 싶다.
'알고리즘' 카테고리의 다른 글
[백준, Java] 31403. A+B-C (0) | 2024.09.20 |
---|---|
[SWEA/Java] 1206. [S/W 문제해결 기본] 1일차 - View (1) | 2024.06.02 |
[SWEA/Java] 1226. [S/W 문제해결 기본] 7일차 - 미로1 (0) | 2024.06.02 |
[SWEA/Java] 1210. [S/W 문제해결 기본] 2일차 - Ladder1 (0) | 2024.06.02 |
[SWEA] 3752. 가능한 시험 점수(Java) (0) | 2024.06.02 |