본문으로 바로가기

[백준 19236] 청소년 상어 -JAVA //le_effort

category 알고리즘 2020. 7. 31. 20:09
청소년 상어

청소년 상어

 

시간 제한메모리 제한제출정답맞은 사람정답 비율
1 초 (추가 시간 없음)512 MB64739630166.593%

문제

아기상어가 성장해 청소년 상어가 되었다.

4×4크기의 공간이 있고, 크기가 1×1인 정사각형 칸으로 나누어져 있다. 공간의 각 칸은 (x, y)와 같이 표현하며, x는 행의 번호, y는 열의 번호이다. 한 칸에는 물고기가 한 마리 존재한다. 각 물고기는 번호와 방향을 가지고 있다. 번호는 1보다 크거나 같고, 16보다 작거나 같은 자연수이며, 두 물고기가 같은 번호를 갖는 경우는 없다. 방향은 8가지 방향(상하좌우, 대각선) 중 하나이다.

오늘은 청소년 상어가 이 공간에 들어가 물고기를 먹으려고 한다. 청소년 상어는 (0, 0)에 있는 물고기를 먹고, (0, 0)에 들어가게 된다. 상어의 방향은 (0, 0)에 있던 물고기의 방향과 같다. 이후 물고기가 이동한다.

물고기는 번호가 작은 물고기부터 순서대로 이동한다. 물고기는 한 칸을 이동할 수 있고, 이동할 수 있는 칸은 빈 칸과 다른 물고기가 있는 칸, 이동할 수 없는 칸은 상어가 있거나, 공간의 경계를 넘는 칸이다. 각 물고기는 방향이 이동할 수 있는 칸을 향할 때까지 방향을 45도 반시계 회전시킨다. 만약, 이동할 수 있는 칸이 없으면 이동을 하지 않는다. 그 외의 경우에는 그 칸으로 이동을 한다. 물고기가 다른 물고기가 있는 칸으로 이동할 때는 서로의 위치를 바꾸는 방식으로 이동한다.

물고기의 이동이 모두 끝나면 상어가 이동한다. 상어는 방향에 있는 칸으로 이동할 수 있는데, 한 번에 여러 개의 칸을 이동할 수 있다. 상어가 물고기가 있는 칸으로 이동했다면, 그 칸에 있는 물고기를 먹고, 그 물고기의 방향을 가지게 된다. 이동하는 중에 지나가는 칸에 있는 물고기는 먹지 않는다. 물고기가 없는 칸으로는 이동할 수 없다. 상어가 이동할 수 있는 칸이 없으면 공간에서 벗어나 집으로 간다. 상어가 이동한 후에는 다시 물고기가 이동하며, 이후 이 과정이 계속해서 반복된다.

img

<그림 1>

<그림 1>은 청소년 상어가 공간에 들어가기 전 초기 상태이다. 상어가 공간에 들어가면 (0, 0)에 있는 7번 물고기를 먹고, 상어의 방향은 ↘이 된다. <그림 2>는 상어가 들어간 직후의 상태를 나타낸다.

img

<그림 2>

이제 물고기가 이동해야 한다. 1번 물고기의 방향은 ↗이다. ↗ 방향에는 칸이 있고, 15번 물고기가 들어있다. 물고기가 있는 칸으로 이동할 때는 그 칸에 있는 물고기와 위치를 서로 바꿔야 한다. 따라서, 1번 물고기가 이동을 마치면 <그림 3>과 같아진다.

img

<그림 3>

2번 물고기의 방향은 ←인데, 그 방향에는 상어가 있으니 이동할 수 없다. 방향을 45도 반시계 회전을 하면 ↙가 되고, 이 칸에는 3번 물고기가 있다. 물고기가 있는 칸이니 서로 위치를 바꾸고, <그림 4>와 같아지게 된다.

img

<그림 4>

3번 물고기의 방향은 ↑이고, 존재하지 않는 칸이다. 45도 반시계 회전을 한 방향 ↖도 존재하지 않으니, 다시 회전을 한다. ← 방향에는 상어가 있으니 또 회전을 해야 한다. ↙ 방향에는 2번 물고기가 있으니 서로의 위치를 교환하면 된다. 이런 식으로 모든 물고기가 이동하면 <그림 5>와 같아진다.

img

<그림 5>

물고기가 모두 이동했으니 이제 상어가 이동할 순서이다. 상어의 방향은 ↘이고, 이동할 수 있는 칸은 12번 물고기가 있는 칸, 15번 물고기가 있는 칸, 8번 물고기가 있는 칸 중에 하나이다. 만약, 8번 물고기가 있는 칸으로 이동하면, <그림 6>과 같아지게 된다.

img

<그림 6>

상어가 먹을 수 있는 물고기 번호의 합의 최댓값을 구해보자.

입력

첫째 줄부터 4개의 줄에 각 칸의 들어있는 물고기의 정보가 1번 행부터 순서대로 주어진다. 물고기의 정보는 두 정수 ai, bi로 이루어져 있고, ai는 물고기의 번호, bi는 방향을 의미한다. 방향 bi는 8보다 작거나 같은 자연수를 의미하고, 1부터 순서대로 ↑, ↖, ←, ↙, ↓, ↘, →, ↗ 를 의미한다.

출력

상어가 먹을 수 있는 물고기 번호의 합의 최댓값을 출력한다.

예제 입력 1 복사

예제 출력 1 복사

예제 입력 2 복사

예제 출력 2 복사

예제 입력 3 복사

예제 출력 3 복사

예제 입력 4 복사

예제 출력 4 복사

 

풀이

삼성 20 상반기 코테 기출문제

 

엄청 고생해서 풀었다... 그 만큼 얻은것도 많을꺼라고 믿는다

map 배열에는 물고기 번호를 넣어주었다.

 

우선 물고기를 표현할 객체를 만들었다.

x,y = 좌표

dir = 방향

alive 는 물고기가 상어에게 잡아먹혔는지 여부를 체크하는 것이다.

 

이 문제에서 물고기는 번호가 작은것 부터 움직여야 한다고 하니 맨처음엔 Fish객체에 물고기 번호도 넣어서 내부 정렬을 통해 작은 것 부터 나오도록 해야하나 라고 생각했는데 굳이 그럴 필요 없이

1~16번 물고기의 정보를 갖는 객체를 만들면 됐다

Fish fish[17] 이렇게 정보를 받으면 된다.

그리고 입력을 받을때 물고기번호를 fish[a] = 값값값값 이런식으로 a 에 넣어주면

1~16번 물고기번호를 입력 받을수 있다.

그리고 작은것 부터 움직여야 하는건 그냥 반복문으로

i=1; i<=16; i++ fish[i] <- 이렇게 접근하면 됐다.

 

dfs 진행방향은 이렇다

  1. 상어가 물고기를 먹는다
  2. 물고기가 이동한다
  3. 상어가 다음칸 혹은 다다음칸으로 이동하고 재귀를 통해 1번 부터 다시 시작한다

 

맨 처음에 상어가 0,0 칸을 먹고 시작하니 dfs를 시작 할 때 인자로 주고 시작하면 된다.

(나는 1,1 부터 시작했다)

dfs의 인자에는 총 4개가 들어간다 상어의 x,y좌표 방향 여태까지 먹은 물고기의 수량

 

위의 코드는 입력을 다 받고 시작 하는건데 상어가 첫 칸을 먹고 시작하니

dfs 시작 전에 잡혔다고 표시 해준 셈이다.

tmp_dir = 1,1에 있는 물고기 방향

tmp_fishNum = 1,1에 있는 물고기 번호

 

 

이제 dfs 함수에서 중요한 부분이 있다.

해당칸에 물고기번호를 가지고있는 map 배열과

물고기 정보를 갖고있는 fish 배열을 복사 해두어야 하는 것이다.

맨 처음 백트래킹을 할 때 나는 단지

이런 식으로만 백트래킹을 진행하면 되는 줄 알았다.

이건 백트래킹의 가장 기초적인 로직이라 (삼성 연구소) 이런식으로 진행하면 되는줄 알았는데

이 문제는 좀 많이 복잡했다.

 

우선 상어는 자신의 진행방향에 따라 물고기를 먹을수 있다.

즉 매번 할 때 마다 다른 물고기를 먹을수 있다.

만약 1번 물고기를 먹었다 치자.

그럼 1번 물고기를 죽이고 dfs함수로 돌아가 1번 물고기가 죽은채로 물고기가 이동한다.

(dfs의 로직은 상어가 물고기를 먹고, 물고기가 움직이고, 상어가 이동하는로직)

그럼 1번 물고기를 먹었다고 가정 했을 경우의 수를 다 훑어 보고

2번 물고기를 먹었다고 가정 했을 경우의 수를 진행 할 때

이미 1번 물고기를 먹었다고 가정하고 진행 할 때 물고기들이 다 이동했기 때문에

2번 물고기를 먹을땐 맨처음 상태의 물고기 상태가아닌 물고기가 1번 물고기가 죽은채로 이미 이동한 상태이다

 

그래서 dfs 안에 copy 배열을 따로 만들었다.

max = Math.max(max,sum)은 지금 다루지 않는다.

copy map과 copy fish에 지금 상태의 물고기와 맵을 저장해준다

여기서 내가 삽질 했던 것 중하나가

copy__fish[i].x = fish[i].x

copy_fish[i].y = fish[i].y 이런식으로 원소 하나하나씩 대입 시켜준게 아니라

이렇게 객체를 통째로 주니 copy_fish와 fish가 같은 주소값을 가지고 있어 로직에 오류가 생겼다.

주의하자 . 객체는 값을 하나씩 넣어줘야 한다.

객체 뭉탱이로 복사를 하면 주소값을 원본과 공유한다

 

그리고 이제 물고기를 이동시켜준다

여기서 또 주의 할 게 있다.

물고기는 다른 물고기가 있는 칸 혹은 빈칸만 이동 할 수 있다.

여기서 빈칸/ 다른물고기가 있는 칸 을 구분해서 로직을 적어줘야한다.

map에서 상어에게 잡아먹힌칸은 0 / 상어가 있는칸은 -1 로 두니

둘의 로직을 하면 map에 저장된 물고기번호를 통해서 fish 배열에 접근을 하려고 하면

이미 잡아 먹힌 칸이라 0 이 되면 fish[0]으로 접근해 틀리게 된다.

 

전체코드