https://www.acmicpc.net/problem/19236
[청소년 상어]
S전자 DS SW테스트를 복원해서 만든 문제
실제 테스트에서 소요시간 2시간 걸렸었다.
문제의 경우 전형적인 시뮬레이션 구현 문제로, 지문를 잘 이해하고 지문대로 구현하면 끝이 난다. ( 실제론 자잘한 오류들을 잡아내다가 시간을 너무 많이 사용함..)
당시의 기억을 살리면서 문제를 풀어보았다.
크게 구현해야 할 부분은,
1. 상어를 방향대로 이동시켜서 해당 위치에 있는 물고기를 잡아먹는 것에 대한 부분
2. 물고기들을 1번부터 차례대로 이동시키는 부분
으로 생각할 수 있다.
그래서 우선 물고기 및 상어의 방향성을 아래와 같이 지문대로 설정해주었다.
1
2
|
static int dx[] = {0,-1,-1,0,1,1,1,0,-1};
static int dy[] = {0,0,-1,-1,-1,0,1,1,1};
|
cs |
전체적으로 실행 되는 재귀 함수로
상어가 현재 위치에서 물고기를 잡아먹을 수 있는 지 확인하고
잡아먹으면 그 위치의 물고기 숫자를 sum에 더해주고, ArrayList에 있는 물고기를 remove한다.
그리고 전역변수로 선언한 sharkX, sharkY(상어의 위치)를 갱신한다.
moveFish() 를 통해서 물고기들의 위치를 이동시킨다. 그 뒤, dir(방향)으로 상어를 이동시켜주고 재귀호출
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
32
33
34
35
36
37
38
39
40
41
42
|
public static void run(ArrayList<Fishes> f, int x, int y, int dir, int sum){
// 먼저 먹을 수 있는지 확인
int res = isEat(f,x,y);
// -1, 먹을 수 없다. 재귀 종료
if(res==-1){
// ans 값보다 현재의 sum이 더 크면 ans값을 변경
if(ans<sum){
ans = sum;
}
return ;
}
// 물고기 번호를 구해서 sum에 더해줌.
int n = f.get(res).number;
sum+=n;
// 방향을 해당 물고기의 x,y 및 방향으로 설정
dir = f.get(res).dir;
sharkX = f.get(res).x;
sharkY = f.get(res).y;
x = f.get(res).x;
y = f.get(res).y;
// 리스트에서 제거
f.remove(res);
// 2. 물고기들의 이동
moveFish(f);
for(int i=1;i<=3;i++){
ArrayList<Fishes> copy = new ArrayList<Fishes>();
// 물고기 리스트가 재귀돌면서 변경되는 것을 막을려고 값을 복사한 copy 로 재귀 실행
copy = copyArr(f);
int nsX = x + i*dx[dir];
int nsY = y + i*dy[dir];
if(nsX<0 || nsY<0 || nsX>=4 || nsY>=4) continue;
run(copy, nsX, nsY, dir, sum);
}
// 해당 위치에서 이동가능한 위치가 없을 경우를 대비해서 만듦
if(sum>ans) ans = sum;
}
|
cs |
moveFish() - 물고기를 주어진 조건대로 이동시킨다.
1번부터 16번까지 차례대로 이동시켜준다.
그리고 isMove()를 통해 물고기 이동상태를 결정한다.
(-1 : 상어 또는 범위 밖으로 이동되는 경우)
(-2 : 이동 가능, 빈 칸으로 이동되는 경우)
(그외 : 다른 물고기와 swap 으로 이동되는 경우)
-1의 경우 dir의 크기를 1씩 증가시키면 된다. 단, 8보다 커지게 되면 다시 1부터 시작하도록 해야한다.
-2는 현재 dir의 방향으로 위치 이동시켜준다.
-3는 물고기 swapFish 라는 교환될 물고기와 숫자와 방향 값을 교환해주면 된다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
public static void moveFish(ArrayList<Fishes> f){
// 1번부터 순서대로 이동
for(int i=1;i<=16;i++){
Fishes fish = new Fishes(0,0,0,0);
for(Fishes ftmp : f){
if(i==ftmp.number) {
fish = ftmp;
break;
}
}
// 이미 잡힌 물고기인 경우
if(fish.number==0) continue;
int dir = fish.dir;
while(true){
// 이동여부 확인 3
int r = isMove(f, i, fish.x, fish.y, dir);
// 해당위치가 범위가 밖이거나 상어인 경우 방향을 회전시킴.
if(r==-1){
dir++;
// 8보다 커지면 맨처음으로
if(dir>8){
dir = 1;
}
}
// 빈칸 이동
else if(r==-2){
int nx = fish.x + dx[dir];
int ny = fish.y + dy[dir];
fish.x = nx;
fish.y = ny;
fish.dir = dir;
break;
}
// swap , 해당 위치의 물고기 번호와 방향만 재설정해서 바꾼다.
else {
int tmpNumber = fish.number;
Fishes swapFish = f.get(r);
fish.number = swapFish.number;
fish.dir = swapFish.dir;
swapFish.number = tmpNumber;
swapFish.dir = dir;
break;
}
}
}
}
public static int isMove(ArrayList<Fishes> f, int idx, int x, int y, int dir){
int nx = x+dx[dir];
int ny = y+dy[dir];
// 다음 위치가 이동할 수 없는 위치인 경우 -1
if(nx<0 || ny<0 || nx>=4 || ny>=4 || (nx==sharkX && ny==sharkY)) return -1;
// 해당위치에 물고기가 있는지 찾음.
for(int i=0;i<f.size();i++){
if(f.get(i).number==idx) continue;
Fishes fish = f.get(i);
if(nx==fish.x && ny==fish.y) return i;
}
// 이동할 수는 있지만, 해당 위치가 빈칸인 경우
return -2;
}
|
cs |
전체적으로 구현 난이도가 높았던 것은 아니라고 생각되나,
시험의 긴장감이 더해지면서 실수하는 부분들이 많이 생겼고 이를 고치고 찾아내는 데에 시간이 많이 걸렸었다.
ArrayList 가 재귀를 돌면서 값이 변형이 발생이 된다 ( 값 전달에서 참조자료형 변수를 넘겨주면 래퍼런스를 ,주소를 가리키는 레퍼런스를 전달한다.)
또 실수한 부분은,
isMove 리턴 값을 -2 가 아닌 0으로 하여서 문제가 생겼다. ArrayList에서 가장 맨 처음 인덱스 0으로 리턴이 for문에서도 리턴이 되어 물고기 이동이 정상적으로 일어나지 않았다.
마찬가지로 , isMove에서 물고기끼리 자리를 바꿀 때 숫자만 바꿔주면 되는데 위치까지 다 변경해버려 물고기 이동이 제대로 안되었다..
총평 :
보다 더 빠르게 풀 수 있는 문제라고 생각이 되고,
문제를 풀 때 보다 더 생각이나 구조를 정확하게 잡고 풀어나가야겠다고 느꼈다.
운이 좋아서 최종 면접까지 갔으나, 면접 결과는 아직 발표 전이므로 다음 하반기까지 SW 테스트를 대비해
문제들을 풀면서 정확성과 속도를 키워야 할 것이다.
전체 소스코드는 아래에
https://github.com/Yuhyeonmo/Data_Structure/blob/master/algo/BOJ_19236.java
'알고리즘' 카테고리의 다른 글
kakao 기출(2021) - 순위 검색 JAVA (0) | 2021.09.07 |
---|---|
kakao 기출(2021) - 신규 아이디 추천 JAVA (0) | 2021.09.03 |
[BOJ_1208] 백준 1208 부분 수열의 합 2 - JAVA (0) | 2020.05.24 |
2020 구글 코드잼 Qualification Round(QR) 참가 후기 (0) | 2020.04.06 |
백준 17071(BOJ 17071) java - 숨바꼭질5 (0) | 2020.03.29 |