본문 바로가기
백준

[백준] code.plus(시뮬레이션과 구현,JAVA)17143번, 낚시왕

by 열정적인 이찬형 2022. 8. 8.

문제 링크

 

17143번: 낚시왕

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다.

www.acmicpc.net


주의사항

  • JAVA를 사용하여 프로그램을 사용하였습니다.
  • 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{ 	
	public static void main(String[] args){
    }
}

문제 설명


접근 방법

 

이 문제에 핵심은

 

1. 낚시왕은 열 방향으로 한 칸씩 이동하며 낚시를 진행하며 가장 가까운 상어를 잡습니다.

2. 상어는 낚시왕이 상어를 잡은 후 방향과 속도에 따른 이동을 진행합니다.

3. 이동한 상어들이 같은 칸에 있을 때 크기가 더 큰 상어가 잡아먹습니다.

4. 크기가 같은 상어는 존재하지 않고, 처음에 같은 공간에 상어가 여러마리 존재하지 않는다.

5. 낚시왕이 잡은 모든 상어의 크기 합을 결과로 출력합니다.

 

알고리즘 진행 순서.

 

1. 입력되는 정보들을 저장합니다.

 

2. 낚시왕이 격자판을 넘어갈 때까지 상어를 잡는 행위와 상어의 이동에 대한 시뮬레이션을 진행합니다.

 

3. 시뮬레이션이 종료 후, 낚시왕이 잡은 상어들 크기의 합을 결과로 출력합니다.

 

 

상어 잡기

 

현재 낚시왕 위치에서 아래 방향으로 가장 가까운 상어를 잡습니다.

 

잡은 상어의 크기를 더합니다.

 

상어 이동

 

1 : 상

 

2 : 하

 

3 : 우

 

4 : 좌

 

상어가 이동할 때 격자판에 벗어나면 방향을 반대로 바꾸고 이동합니다.

 

 

예제입력 4.

 

1. 입력되는 정보들을 저장합니다.

 

R : 2

C : 2

M : 4

현재 낚시왕  
상어1(속도 : 1, 방향 : 1, 크기 : 1) 상어3(속도 : 1, 방향 : 2, 크기 : 3)
상어4(속도 : 2, 방향 : 1, 크기 : 4) 상어2(속도 : 2, 방향 : 2, 크기 : 2)

 

2. 낚시왕이 격자판을 넘어갈 때까지 상어를 잡는 행위와 상어의 이동에 대한 시뮬레이션을 진행합니다.

 

상어 잡기!

현재 낚시왕  
  상어3(속도 : 1, 방향 : 2, 크기 : 3)
상어4(속도 : 2, 방향 : 1, 크기 : 4) 상어2(속도 : 2, 방향 : 2, 크기 : 2)

 

가장 가까운 상어1을 잡았습니다.

크기 + 1

 

상어 이동!

현재 낚시왕  
   
상어4(속도 : 2, 방향 : 1, 크기 : 4) 상어2(속도 : 2, 방향 : 2, 크기 : 2)
상어3(속도 : 1, 방향 : 2, 크기 : 3)

상어가 같은 칸에 존재하므로 크기가 큰 상어3이 상어2를 잡아먹습니다.

현재 낚시왕  
   
상어4(속도 : 2, 방향 : 1, 크기 : 4) 상어3(속도 : 1, 방향 : 2, 크기 : 3)

 

낚시왕 이동!

상어 잡기!

  현재 낚시왕
   
상어4(속도 : 2, 방향 : 1, 크기 : 4)  

가장 가까운 상어3을 잡았습니다.

크기 + 3

 

더 이상 낚시왕이 상어를 잡지 않기 때문에 상어가 이동하지 않아도 상관없으므로 생략!

 

3. 시뮬레이션이 종료 후, 낚시왕이 잡은 상어들 크기의 합을 결과로 출력합니다.

 

지금까지 잡은 상어 크기의 합은 1 + 3 = 4을 결과로 출력합니다.

 

  • BufferedReader를 사용하여 입력 값을 받았습니다.
  • StringTokenizer를 이용하여 입력된 정보에 대하여 나누었습니다.
  • 낚시왕이 이동하는 동안 getShark,sharkMove를 순차적으로 실행하여 상어 잡기, 상어 이동에 대한 시뮬레이션을 진행합니다.
  • 낚시왕의 움직임이 멈춘 뒤 잡은 상어 크기의 합을 BufferedWriter 저장하였습니다.
  • BufferedWriter에 저장된 결과값을 출력하였습니다.
  • getShark함수는 낚시왕이 상어를 잡는 것을 진행합니다.
  • sharkMove함수는 상어의 정보를 토대로 이동을 진행합니다.
  • directionChange함수는 상어가 격자판을 벗어나도록 이동할 때 방향을 바꾸는 것을 진행합니다.
  • outBound함수는 상어가 이동할 때 격자판에 벗어나는지 확인합니다.

 

import java.io.*;
import java.util.*;

public class Main {
    //상어 정보 관련 클래스
    static class sharkInfo{
        int r, c, s, d, z;	//r,c : 위치, s : 속도, d : 방향, z : 크기
        boolean dead;		//상어가 죽었는지 확인하는 변수
        public sharkInfo(int r, int c, int s, int d, int z, boolean dead) {
            this.r = r;
            this.c = c;
            this.s = s;
            this.d = d;
            this.z = z;
            this.dead = dead;
        }
    }
    static int R,C,M, answer = 0;
    static int[][] sharks;		//상어 번호들이 어디에 존재하는지 저장 배열
    static int[] dx = {0, 0, 0, 1, -1};	//상어 이동 x변경값
    static int[] dy = {0, -1, 1, 0, 0};	//상어 이동 y변경값
    static ArrayList<sharkInfo> info = new ArrayList<>();	//상어 정보 저장 리스트
    public static void main(String[] args) throws IOException {
        //입력값 처리하는 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //결과값 출력하는 BufferedWriter
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        R = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        sharks = new int[R][C];
        //상어1부터 존재할 것이므로 상어0은 없는 값으로 저장
        info.add(new sharkInfo(0,0,0,0,0, false));
        //상어 정보 저장
        for(int i=1;i<=M;i++){
            st = new StringTokenizer(br.readLine()," ");
            int r = Integer.parseInt(st.nextToken())-1;
            int c = 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)
                s = s % ((R-1)*2);
            else
                s = s % ((C-1)*2);

            sharks[r][c] = i;	
            info.add(new sharkInfo(r,c,s,d,z, false));
        }
        //C-1번 시뮬레이션 시작
        for(int i=0;i<C-1;i++){		//for문으로 낚시왕 위치 이동
            getShark(i);	//상어 잡기
            sharkMove();	//상어 이동
        }
        getShark(C-1);	//마지막은 상어잡기만 진행합니다.
        bw.write(answer + "");	//잡은 크기의 합 BufferedWriter 저장
        bw.flush();		//결과 출력
        bw.close();
        br.close();
    }
    //낚시왕이 상어를 잡는 함수
    static void getShark(int c){
        //현재 낚시왕 위치에서 아래로 내려가며 가장 가까운 상어를 잡기!
        for(int i=0;i<R;i++){
            if(sharks[i][c] != 0){
                answer += info.get(sharks[i][c]).z;	//잡은 상어 크기 더하기
                info.get(sharks[i][c]).dead = true;	//해당 상어 죽은 상태로 변경
                sharks[i][c] = 0;
                return;
            }
        }
    }
    //상어 이동을 진행하는 함수
    static void sharkMove(){
        //각 상어 정보를 토대로 이동
        for(int i=1;i<info.size();i++){
            sharkInfo cur = info.get(i);
            if(cur.dead)
                continue;
            if(sharks[cur.r][cur.c] == i)
                sharks[cur.r][cur.c] = 0;
            for(int j=0;j<cur.s;j++){
                int tempR = cur.r + dy[cur.d];
                int tempC = cur.c + dx[cur.d];
                if(outBound(tempR,tempC)){
                    directionChange(i, cur.d);
                    tempR = cur.r + dy[cur.d];
                    tempC = cur.c + dx[cur.d];
                }
                cur.r = tempR;
                cur.c = tempC;
            }
            //이동한 칸에 다른 이동한 상어 존재할 때 크기가 더 큰 상어가 잡아먹기
            if(sharks[cur.r][cur.c] < i && sharks[cur.r][cur.c] > 0){
                if(info.get(sharks[cur.r][cur.c]).z > cur.z)
                    cur.dead = true;
                else{
                    info.get(sharks[cur.r][cur.c]).dead = true;
                    sharks[cur.r][cur.c] = i;
                }
            }else
                sharks[cur.r][cur.c] = i;
        }
    }
    //방향을 반대로 바꾸는 함수
    static void directionChange(int index, int direction){
        if(direction%2==0)
            info.get(index).d = direction-1;
        else
            info.get(index).d = direction+1;
    }
    //상어가 이동할 때 격자판에 벗어나는지 확인하는 함수
    static boolean outBound(int r, int c){
        if(r>=0 && c>=0 && r<R && c < C)
            return false;
        return true;

    }
}

댓글