@시뮬레이션 / 4h 이상
처음에는 오 인덱스 조절만 잘 하면 쉽겠다 하고 풀었는데
이게 웬걸.. 테케도 안맞아서 그때부터 멘붕되고
값을 넣는 족족 stackoverflow로 터져버려서 내 멘탈도 같이 터진 문제였다..
ㅎㅎ
나중에는 swea의 댓글을 참고하면서 코드를 고쳐나갔는데
테케 40->42->43->46->49 순으로 맞아서 진짜 인내심 테스트 하는 줄 알았다.
마지막에 pass 떴을 때에는 되는건 좋은데 왜 되는지 스스로 이해가 안돼서 더 괴로웠다 ㅠㅠ
알고보니 문제를 잘못 이해했던 거였다. 주어진 대로만 풀면 적당한 문제였는데..
문제 링크
https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRF8s6ezEDFAUo
구현 포인트
1. 블럭에 부딪혀서 방향이 바뀌는 부분
일단 기본 방향을 상 0, 좌 1, 하 2, 우 3 으로 둔다 ((방향 + 2) % 4 == 반대방향이 되게 하기 위해)
그리고 2차원 배열을 만들었다. dir[블럭번호][지금 방향] = 바뀔 방향 값을 넣어준다
1번블록 | 2번블록 | 3번블록 | 4번블록 | 5번블록 | |
상0 | 하 2 | 우 3 | 좌 1 | 하 2 | 하 2 |
하1 | 상 0 | 하 2 | 우 3 | 우 3 | 우 3 |
좌2 | 우 3 | 상 0 | 싱 0 | 좌 1 | 상 0 |
우3 | 좌 1 | 좌 1 | 히 2 | 상 0 | 좌 1 |
이렇게 하면 방향을 편리하게 바꿀 수 있다.
단점) 단점은, 문제가 풀리지 않을 때 혹시 여기서 실수한 게 아닐까 하고 불안해져서 자꾸 확인하게 된다는 점..?
2. 가장자리 처리
이 부분은 다른 분의 댓글을 보고 알았는데, 꿀팁이라 추가했다.
가장자리에 부딪히면 반대방향으로 튕기는데, 원래같으면 따로 처리를 해 줘야 하겠지만
이 경우는 맵을 [N+2][N+2] 크기로 선언하고 가장자리 칸을 다 5로 채워버리면 된다.
예외 처리(아예 벗어날 경우)도 더이상 필요하지 않다. 벗어날 일이 없으니까.
(그래도 걱정돼서 물어봤더니 논리가 만약을 이기면 된다고 하더라..ㅠㅠ..)
3. 웜홀 처리
웜홀을 위한 3차원 배열을 사용했다. warmhole[웜홀번호][1번째,2번째웜홀][x면 0, y면 1]
그래서 만약 6번 웜홀에 들어간다면, 반대편 웜홀의 좌표는 이 배열로 바로 구할 수 있다.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Solution {
private static int N, maxScore, sx, sy, sd, map[][], wormhole[][][];
private static int[] dx = {-1, 0, 1, 0}, dy = {0, -1, 0, 1};
private static int[][] dir = {{0, 0, 0, 0}, {2, 0, 3, 1}, {3, 2, 0, 1}, {1, 3, 0, 2}, {2, 3, 1, 0}, {2, 3, 0, 1}};
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
StringBuilder sb = new StringBuilder();
int T = Integer.parseInt(br.readLine().trim());
for (int t = 1; t <= T; t++) {
maxScore = 0;
wormhole = new int[11][2][2];
N = Integer.parseInt(br.readLine().trim());
map = new int[N + 2][N + 2];
boolean[] wormholeVisit = new boolean[11];
for (int i = 1; i <= N; i++) {
st = new StringTokenizer(br.readLine().trim());
for (int j = 1; j <= N; j++) {
map[i][j] = Integer.parseInt(st.nextToken().trim());
if (map[i][j] >= 6) {
if (!wormholeVisit[map[i][j]]) {
wormhole[map[i][j]][0][0] = i;
wormhole[map[i][j]][0][1] = j;
wormholeVisit[map[i][j]] = true;
} else {
wormhole[map[i][j]][1][0] = i;
wormhole[map[i][j]][1][1] = j;
}
}
}
}
for (int i = 0; i < N + 2; i++)
map[0][i] = map[N + 1][i] = map[i][0] = map[i][N + 1] = 5;
startPoint();
sb.append("#" + t + " " + (maxScore) + "\n");
}
System.out.println(sb);
}
private static void startPoint() {
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (map[i][j] == 0) {
for (int d = 0; d < 4; d++) {
sx = i; sy = j; sd = d;
move();
}
}
}
}
}
private static void move() {
int x = sx, y = sy, d = sd, score = 0, nx, ny;
boolean overlap = false;
while (true) {
// if (x < 0 || x >= N + 2 || y < 0 || y >= N + 2) return;
//원래라면 해 줘야 하지만, 가장자리를 전부 5로 채웠기 때문에 벗어날 일이 없으므로 안 해줘도 된다.
if (overlap) { //처음 들어왔을 때를 제욓하고 종료 조건 체크
if ((x == sx && y == sy) || map[x][y] == -1) {
if (maxScore < score)
maxScore = score;
return;
}
}
nx = x + dx[d];
ny = y + dy[d];
overlap = true;
// if (nx < 0 || nx >= N + 2 || ny < 0 || ny >= N + 2) {
// return;
// }
//원래라면 해 줘야 하지만, 가장자리를 전부 5로 채웠기 때문에 벗어날 일이 없으므로 안 해줘도 된다.
if ((nx == sx && ny == sy) || map[nx][ny] == -1) { //종료 조건
if (maxScore < score)
maxScore = score;
return;
}
if (map[nx][ny] >= 6) { //웜홀
if (wormhole[map[nx][ny]][0][0] == nx && wormhole[map[nx][ny]][0][1] == ny) {
x = wormhole[map[nx][ny]][1][0];
y = wormhole[map[nx][ny]][1][1];
} else {
x = wormhole[map[nx][ny]][0][0];
y = wormhole[map[nx][ny]][0][1];
}
} else if (map[nx][ny] >= 1) { //블럭
x = nx;
y = ny;
d = dir[map[nx][ny]][d];
score++;
} else if (map[nx][ny] == 0){
x = nx;
y = ny;
}
}
}
}
삽질 포인트
1. 핀볼이 맨 윗줄에서 시작하고, 윗방향으로 출발하면 출발하자마자 벽을 만나서 제자리로 돌아오고, 방향만 반대로 바뀌게 된다.
이 때는 게임을 종료해야 한다.
이 부분을 이해하지 못해서 꽤나 오래 고생했다.
사실 간단하게 생각해 보면, 벽에 부딪혔다가 제자리로 돌아오면 게임이 끝난다고 애초에 명시되어 있는데, 왜 그렇게 오래 고민했는지 모르겠다.
2. 가장 헷갈렸던 부분은 한 턴에서 어디까지 처리를 해 줘야 하는 것인가? 이다.
그게 너무 헷갈려서 처음에는 x = 1, y = 1 칸에서 우측으로 이동해서 nx = 1, ny = 2가 되었을 때,
벽을 만나서 아래로 내려가야 한다면, 내려가는 처리까지 이 턴에서 한번에 처리해 줬다.
그러니 될 리가 없지..ㅎ
반복문을 돌 때는, 한번 이동하는 것에 대한 처리만 해 주면 된다.
다음 턴은, 그 턴에서 알아서 하게 두면 된다(대신, 이렇게 구현한다면 시작 부분에서 경계 체크등의 코드를 넣어야겠지).
문제에서 시키는 대로 하자!!!
힘들었지만 풀어서 뿌듯하다.
그렇지만 다시는 하고 싶지 않은 고생이었다..ㅎㅎ
끝!!
'algorithm > SW Expert Academy' 카테고리의 다른 글
[SWEA] 8382.방향 전환 (java) / 시뮬레이션 (0) | 2020.03.05 |
---|---|
[SWEA] 2105.디저트 카페 / DFS (0) | 2020.01.28 |
[SWEA] 4008.숫자 만들기 / Next-Permutation (0) | 2020.01.26 |
[SWEA] 1953.탈주범 검거 (java) / BFS (0) | 2020.01.26 |
[SWEA] 2117.홈 방범 서비스 (java) / BFS 또는 List 활용 (0) | 2020.01.26 |
댓글