[JAVA] 17143 - 낚시왕 💛1 : 영감을 주는 시뮬레이션 문제 (왕복은 실제로 이동하는 것이 아니다!)

2026. 4. 9. 16:25·Problem Solve

들어가며

https://www.acmicpc.net/problem/17143

정석적인 시뮬레이션 문제다. 문제를 읽고 필요한 풀이를 직관적으로 정리하자면

1. 상어잡기

2. 상어 이동

3. 이동 할때 두마리 이상의 상어가 있다면 서로 싸워라.

본문으로

딱 읽었을 때 익숙한 느낌의 좌표 이동 시키고~ 없애고~ 하는 식의 시뮬레이션 문제였다. 상어 잡는 로직과 상어 이동하는 로직을 신경써서 아래와 같이 작성했다.

public class Main {

    static int ret, Y, X, M;

    static class Shark {
        int s;
        int d;
        int z;

        Shark(int s, int d, int z) {
            this.s = s;
            this.d = d;
            this.z = z;
        }
    }

    static class After {
        int h;
        int d;

        After(int h, int d) {
            this.h = h;
            this.d = d;
        }
    }

    static Shark[][] makeMap(Shark[][] maps) {
        Shark[][] dMaps = new Shark[Y][X];

        for (int i = 0; i < Y; i++) {
            for (int j = 0; j < X; j++) {
                if (maps[i][j] != null) {
                    Shark shark = maps[i][j];
                    if (shark.d <= 2) { // 위 아래
                        After after = goY(i, shark.s, shark.d);
                        shark.d = after.d;
                        if (dMaps[after.h][j] != null) {
                            if (dMaps[after.h][j].z < shark.z) {
                                dMaps[after.h][j] = shark;
                            }
                        } else {
                            dMaps[after.h][j] = shark;
                        }
                    } else { // 좌우
                        After after = goX(j, shark.s, shark.d);
                        shark.d = after.d;
                        if (dMaps[i][after.h] != null) {
                            if (dMaps[i][after.h].z < shark.z) {
                                dMaps[i][after.h] = shark;
                            }
                        } else {
                            dMaps[i][after.h] = shark;
                        }
                    }
                }
            }
        }

        return dMaps;
    }

    static After goY(int here, int s, int d) {
        while (s > 0) {
            if (d == 1) { // 위
                if (here - 1 < 0) {
                    d = 2;
                    continue;
                }
                here--;
            } else { // 2 -> 아래
                if (here + 1 >= Y) {
                    d = 1;
                    continue;
                }
                here++;
            }
            s--;
        }
        return new After(here, d);
    }

    static After goX(int here, int s, int d) {
        while (s > 0) {
            if (d == 3) { // -> 오른쪽
                if (here + 1 >= X) {
                    d = 4;
                    continue;
                }
                here++;

            } else { // 4 -> 왼쪽
                if (here - 1 < 0) {
                    d = 3;
                    continue;
                }
                here--;
            }
            s--;
        }
        return new After(here, d);
    }

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        Y = Integer.parseInt(st.nextToken());
        X = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        Shark[][] maps = new Shark[Y][X];

        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int y = Integer.parseInt(st.nextToken()) - 1;
            int x = Integer.parseInt(st.nextToken()) - 1;
            int s = Integer.parseInt(st.nextToken());
            int d = Integer.parseInt(st.nextToken());
            int z = Integer.parseInt(st.nextToken());
            maps[y][x] = new Shark(s, d, z);
        }

        ret = 0;
        // 왼 -> 오
        for (int i = 0; i < X; i++) {
            // 현재 x에서 땅과 가장 가까운 상어잡기
            for (int j = 0; j < Y; j++) {
                if (maps[j][i] != null) {
                    ret += maps[j][i].z;
                    maps[j][i] = null;
                    break; // 잡으면 바로 넘어가기
                }
            }

            // 상어 이동
            maps = makeMap(maps);
        }

        System.out.println(ret);
    }
}


풀고 나서,, 다른 분들의 풀이를 참고했는데 너무 괜찮은 사고가 있어서 정리하려고 한다.

이전의 로직은 상어가 벽을 만났을 때 방향을 바꿔 이동하는 것을 실제로 다 구현했었다.(벽을 만날때까지 실제로 이동했다는 뜻) 

사실 상어의 이동 후 위치 결과가 중요하지, 이동 과정은 중요하지 않기 때문에 왔다갔다 하는 것을 실제로 왔다갔다 할 필요가 없다는 것이다.

아래와 같은 좌표에서 0에서 시작한다고 할때, 튕기면서 이동한다는 것을 확인할 수 있다.

0 1 2 3

// 아래와 같은 식으로 튕기면서 움직일 것.
0 -> 1 -> 2 -> 3 -> 2 -> 1 -> 0 -> 1 -> 2 -> 3 ...

당연한 말이지만, 0칸에서 (R-1)칸 까지 가려면 R-1칸을 이동해야 한다. 8칸을 간다고 치면 왔다갔다 한번 하고 2칸을 앞으로 가기만 하면 된다. 이를 즉 실제로 이동할 거리를  s %= 2 * (R - 1) 로 정리할 수 있다. 아래는 이 최적화 식을 적용한 코드이다.

public class Main {

    static int ret, Y, X, M;

    static class Shark {
        int s;
        int d;
        int z;

        Shark(int s, int d, int z) {
            this.s = s;
            this.d = d;
            this.z = z;
        }
    }

    static class After {
        int h;
        int d;

        After(int h, int d) {
            this.h = h;
            this.d = d;
        }
    }

    static Shark[][] makeMap(Shark[][] maps) {
        Shark[][] dMaps = new Shark[Y][X];

        for (int i = 0; i < Y; i++) {
            for (int j = 0; j < X; j++) {
                if (maps[i][j] != null) {
                    Shark shark = maps[i][j];
                    if (shark.d <= 2) { // 위 아래
                        After after = goY(i, shark.s, shark.d);
                        shark.d = after.d;
                        if (dMaps[after.h][j] != null) {
                            if (dMaps[after.h][j].z < shark.z) {
                                dMaps[after.h][j] = shark;
                            }
                        } else {
                            dMaps[after.h][j] = shark;
                        }
                    } else { // 좌우
                        After after = goX(j, shark.s, shark.d);
                        shark.d = after.d;
                        if (dMaps[i][after.h] != null) {
                            if (dMaps[i][after.h].z < shark.z) {
                                dMaps[i][after.h] = shark;
                            }
                        } else {
                            dMaps[i][after.h] = shark;
                        }
                    }
                }
            }
        }

        return dMaps;
    }

    static After goY(int here, int s, int d) {
        while (s-- > 0) {
            if (d == 1) { // 위
                if (here - 1 < 0) {
                    d = 2;
                    here++;
                } else {
                    here--;
                }
            } else { // 2 -> 아래
                if (here + 1 >= Y) {
                    d = 1;
                    here--;
                } else {
                    here++;
                }
            }
        }
        return new After(here, d);
    }

    static After goX(int here, int s, int d) {
        while (s-- > 0) {
            if (d == 3) { // -> 오른쪽
                if (here + 1 >= X) {
                    d = 4;
                    here--;
                } else {
                    here++;
                }

            } else { // 4 -> 왼쪽
                if (here - 1 < 0) {
                    d = 3;
                    here++;
                } else {
                    here--;
                }
            }
        }
        return new After(here, d);
    }

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        Y = Integer.parseInt(st.nextToken());
        X = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        Shark[][] maps = new Shark[Y][X];

        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int y = Integer.parseInt(st.nextToken()) - 1;
            int x = Integer.parseInt(st.nextToken()) - 1;
            int s = Integer.parseInt(st.nextToken());
            int d = Integer.parseInt(st.nextToken());
            int z = Integer.parseInt(st.nextToken());

			// 속력 주기 최적화
            if (d == 1 || d == 2) {
                if (Y > 1) {
                    s %= (2 * (Y - 1));
                }
            } else if (d == 3 || d == 4) {
                if (X > 1) {
                    s %= (2 * (X - 1));
                }
            }
            maps[y][x] = new Shark(s, d, z);
        }

        ret = 0;
        // 왼 -> 오
        for (int i = 0; i < X; i++) {
            // 현재 x에서 땅과 가장 가까운 상어잡기
            for (int j = 0; j < Y; j++) {
                if (maps[j][i] != null) {
                    ret += maps[j][i].z;
                    maps[j][i] = null;
                    break; // 잡으면 바로 넘어가기
                }
            }

            // 상어 이동
            maps = makeMap(maps);
        }

        System.out.println(ret);
    }
}

전의 코드와 시간이 확 줄었음을 확인 할 수 있다!!

마무리하며

문제를 그대로 믿고 벽을 만날 때까지 직접가버리니... 시간복잡도가 매우 증가한다.. 실제로 앞으로 2칸만 가면 되는 것을 내 코드는 500번 왕복 후 앞으로 두번 가고 있던 것이었다...

우여곡절로 정답 코드를 내긴 했지만, 조금 더 여유롭게 이런 풀이도 적용할 수 있으면 참 좋겠다. 

앞으로도 왕복하는 문제가 있다면 (이동거리) %= 2 * (전체거리 -1) 이런 식의 Thinking을 꼭 생각하자!

'Problem Solve' 카테고리의 다른 글

[JAVA] 2632 - 피자판매 💛2 : 값이 아닌 경우의 수를 저장하자. + 원형 자료구조는 선형 자료구조로 피자!  (0) 2026.04.15
[JAVA] 15685 - 드래곤 커브 💛3: 기하 문제라면 당황하지 말고 규칙을 찾아보자.  (0) 2026.04.14
[JAVA] 17825 - 주사위 윷놀이 💛2: 한땀한땀 만들어야하는 시뮬레이션 문제(집중하자...)  (0) 2026.04.07
[JAVA] 15662 - 톱니바퀴 (2) 💛5: 역할을 확실하게 나누자..! - 시뮬레이션 정복기  (0) 2026.04.01
[JAVA] 17406 - 배열 돌리기 4 💛4 : 복잡한 2차원 배열 문제는 복잡도를 줄이기 위해 1차원으로 뽑자!  (0) 2026.03.31
'Problem Solve' 카테고리의 다른 글
  • [JAVA] 2632 - 피자판매 💛2 : 값이 아닌 경우의 수를 저장하자. + 원형 자료구조는 선형 자료구조로 피자!
  • [JAVA] 15685 - 드래곤 커브 💛3: 기하 문제라면 당황하지 말고 규칙을 찾아보자.
  • [JAVA] 17825 - 주사위 윷놀이 💛2: 한땀한땀 만들어야하는 시뮬레이션 문제(집중하자...)
  • [JAVA] 15662 - 톱니바퀴 (2) 💛5: 역할을 확실하게 나누자..! - 시뮬레이션 정복기
노을을
노을을
진인사대천명
  • 노을을
    노을의 개발일기장
    노을을
  • 전체
    오늘
    어제
    • All (105) N
      • Java & Kotlin (16)
      • Problem Solve (46)
      • Spring (4)
      • Infra (3) N
      • DB (2)
      • Project (2)
        • SOMA (1)
        • OJik (1)
      • OpenSource (3)
      • Various Dev (23)
        • 우아한테크코스 (9)
        • Git&Github (2)
        • Unity (12)
      • Book (3)
      • Writing (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    시뮬레이션
    java
    코딩
    우아한테크코스
    8기
    알고리즘
    contribute
    개발
    비트마스킹
    코테
    합격
    자바
    github
    개발자
    오픈소스
    유니티
    게임개발
    백준
    프리코스
    트러블슈팅
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
노을을
[JAVA] 17143 - 낚시왕 💛1 : 영감을 주는 시뮬레이션 문제 (왕복은 실제로 이동하는 것이 아니다!)
상단으로

티스토리툴바